mirror of
https://github.com/Eugeny/tabby
synced 2024-12-13 06:42:44 +00:00
Mark duplicate hotkeys
This commit is contained in:
parent
bc243a2741
commit
72bc58332d
7 changed files with 77 additions and 28 deletions
|
@ -3,6 +3,11 @@ export interface HotkeyDescription {
|
||||||
name: string
|
name: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface Hotkey {
|
||||||
|
strokes: string[] | string; // may be a sequence of strokes
|
||||||
|
isDuplicate: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extend to provide your own hotkeys. A corresponding [[ConfigProvider]]
|
* Extend to provide your own hotkeys. A corresponding [[ConfigProvider]]
|
||||||
* must also provide the `hotkeys.foo` config options with the default values
|
* must also provide the `hotkeys.foo` config options with the default values
|
||||||
|
|
|
@ -256,6 +256,11 @@ multi-hotkey-input {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.item:has(.duplicate) {
|
||||||
|
background-color: theme-color('danger');
|
||||||
|
border: 1px solid theme-color('danger');
|
||||||
|
}
|
||||||
|
|
||||||
.add {
|
.add {
|
||||||
color: #777;
|
color: #777;
|
||||||
padding: 4px 10px 0;
|
padding: 4px 10px 0;
|
||||||
|
@ -265,6 +270,11 @@ multi-hotkey-input {
|
||||||
&:hover { background: darken($body-bg2, 5%); }
|
&:hover { background: darken($body-bg2, 5%); }
|
||||||
&:active { background: darken($body-bg2, 15%); }
|
&:active { background: darken($body-bg2, 15%); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.add:has(.duplicate), .item:has(.duplicate) .body, .item:has(.duplicate) .remove {
|
||||||
|
&:hover { background: darken(theme-color('danger'), 5%); }
|
||||||
|
&:active { background: darken(theme-color('danger'), 15%); }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
hotkey-input-modal {
|
hotkey-input-modal {
|
||||||
|
|
|
@ -162,6 +162,11 @@ multi-hotkey-input {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.item:has(.duplicate) {
|
||||||
|
background-color: theme-color('danger');
|
||||||
|
border: 1px solid theme-color('danger');
|
||||||
|
}
|
||||||
|
|
||||||
.add {
|
.add {
|
||||||
color: #777;
|
color: #777;
|
||||||
padding: 4px 10px 0;
|
padding: 4px 10px 0;
|
||||||
|
@ -171,6 +176,11 @@ multi-hotkey-input {
|
||||||
&:hover { background: darken($body-bg2, 5%); }
|
&:hover { background: darken($body-bg2, 5%); }
|
||||||
&:active { background: darken($body-bg2, 15%); }
|
&:active { background: darken($body-bg2, 15%); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.add:has(.duplicate), .item:has(.duplicate) .body, .item:has(.duplicate) .remove {
|
||||||
|
&:hover { background: darken(theme-color('danger'), 5%); }
|
||||||
|
&:active { background: darken(theme-color('danger'), 15%); }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
hotkey-input-modal {
|
hotkey-input-modal {
|
||||||
|
|
|
@ -14,6 +14,6 @@ h3.mb-3(translate) Hotkeys
|
||||||
span.ml-2.text-muted ({{hotkey.id}})
|
span.ml-2.text-muted ({{hotkey.id}})
|
||||||
.col-4.pr-5
|
.col-4.pr-5
|
||||||
multi-hotkey-input(
|
multi-hotkey-input(
|
||||||
[model]='getHotkey(hotkey.id) || []',
|
[hotkeys]='getHotkeys(hotkey.id) || []',
|
||||||
(modelChange)='setHotkey(hotkey.id, $event)'
|
(hotkeysChange)='setHotkeys(hotkey.id, $event)'
|
||||||
)
|
)
|
||||||
|
|
|
@ -7,6 +7,7 @@ import {
|
||||||
HotkeysService,
|
HotkeysService,
|
||||||
HostAppService,
|
HostAppService,
|
||||||
} from 'tabby-core'
|
} from 'tabby-core'
|
||||||
|
import { Hotkey } from 'tabby-core/src/api/hotkeyProvider'
|
||||||
|
|
||||||
_('Search hotkeys')
|
_('Search hotkeys')
|
||||||
|
|
||||||
|
@ -30,28 +31,44 @@ export class HotkeySettingsTabComponent {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
getHotkey (id: string) {
|
getHotkeys (id: string): Hotkey[] {
|
||||||
let ptr = this.config.store.hotkeys
|
let ptr = this.config.store.hotkeys
|
||||||
for (const token of id.split(/\./g)) {
|
for (const token of id.split(/\./g)) {
|
||||||
ptr = ptr[token]
|
ptr = ptr[token]
|
||||||
}
|
}
|
||||||
return ptr
|
return (ptr || []).map(hotkey => this.detectDuplicates(hotkey))
|
||||||
}
|
}
|
||||||
|
|
||||||
setHotkey (id: string, value) {
|
setHotkeys (id: string, hotkeys: Hotkey[]) {
|
||||||
let ptr = this.config.store
|
let ptr = this.config.store
|
||||||
let prop = 'hotkeys'
|
let prop = 'hotkeys'
|
||||||
for (const token of id.split(/\./g)) {
|
for (const token of id.split(/\./g)) {
|
||||||
ptr = ptr[prop]
|
ptr = ptr[prop]
|
||||||
prop = token
|
prop = token
|
||||||
}
|
}
|
||||||
ptr[prop] = value
|
ptr[prop] = hotkeys.map(hotkey =>
|
||||||
|
hotkey.strokes.length === 1 && Array.isArray(hotkey.strokes)
|
||||||
|
? hotkey.strokes[0]
|
||||||
|
: hotkey.strokes,
|
||||||
|
)
|
||||||
this.config.save()
|
this.config.save()
|
||||||
}
|
}
|
||||||
|
|
||||||
hotkeyFilterFn (hotkey: HotkeyDescription, query: string): boolean {
|
hotkeyFilterFn (hotkey: HotkeyDescription, query: string): boolean {
|
||||||
// eslint-disable-next-line @typescript-eslint/restrict-plus-operands
|
const s = hotkey.name + hotkey.id + this.getHotkeys(hotkey.id).map(h => h.strokes).toString()
|
||||||
const s = hotkey.name + hotkey.id + (this.getHotkey(hotkey.id) || []).toString()
|
|
||||||
return s.toLowerCase().includes(query.toLowerCase())
|
return s.toLowerCase().includes(query.toLowerCase())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private detectDuplicates (strokes: string[] | string): Hotkey {
|
||||||
|
const allHotkeys = Object
|
||||||
|
.values(this.config.store.hotkeys)
|
||||||
|
.filter((value: unknown) => Array.isArray(value))
|
||||||
|
.flat()
|
||||||
|
|
||||||
|
const isDuplicate = allHotkeys
|
||||||
|
.filter(hotkey => JSON.stringify(hotkey) === JSON.stringify(strokes))
|
||||||
|
.length > 1
|
||||||
|
|
||||||
|
return { strokes, isDuplicate }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
.item(*ngFor='let item of model')
|
.item(*ngFor='let hotkey of hotkeys')
|
||||||
.body((click)='editItem(item)')
|
.body((click)='editItem(hotkey)')
|
||||||
.stroke(*ngFor='let stroke of item') {{stroke}}
|
.stroke(*ngFor='let stroke of hotkey.strokes')
|
||||||
.remove((click)='removeItem(item)') ×
|
span(*ngIf='!hotkey.isDuplicate', translate) {{stroke}}
|
||||||
|
span.duplicate(*ngIf='hotkey.isDuplicate', translate) {{stroke}}
|
||||||
|
.remove((click)='removeItem(hotkey)') ×
|
||||||
|
|
||||||
.add((click)='addItem()', translate) Add...
|
.add((click)='addItem()', translate) Add...
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy } from '@angular/core'
|
import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy } from '@angular/core'
|
||||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
||||||
import { HotkeyInputModalComponent } from './hotkeyInputModal.component'
|
import { HotkeyInputModalComponent } from './hotkeyInputModal.component'
|
||||||
|
import { Hotkey } from 'tabby-core/src/api/hotkeyProvider'
|
||||||
|
|
||||||
/** @hidden */
|
/** @hidden */
|
||||||
@Component({
|
@Component({
|
||||||
|
@ -10,37 +11,41 @@ import { HotkeyInputModalComponent } from './hotkeyInputModal.component'
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
})
|
})
|
||||||
export class MultiHotkeyInputComponent {
|
export class MultiHotkeyInputComponent {
|
||||||
@Input() model: string[][] = []
|
@Input() hotkeys: Hotkey[] = []
|
||||||
@Output() modelChange = new EventEmitter()
|
@Output() hotkeysChange = new EventEmitter()
|
||||||
|
|
||||||
constructor (
|
constructor (
|
||||||
private ngbModal: NgbModal,
|
private ngbModal: NgbModal,
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
ngOnChanges (): void {
|
ngOnChanges (): void {
|
||||||
if (typeof this.model === 'string') {
|
this.hotkeys = this.hotkeys.map(hotkey => typeof hotkey.strokes === 'string' ? { ...hotkey, strokes: [hotkey.strokes] } : hotkey)
|
||||||
this.model = [this.model]
|
|
||||||
}
|
|
||||||
this.model = this.model.map(item => typeof item === 'string' ? [item] : item)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
editItem (item: string[]): void {
|
editItem (item: Hotkey): void {
|
||||||
this.ngbModal.open(HotkeyInputModalComponent).result.then((value: string[]) => {
|
this.ngbModal.open(HotkeyInputModalComponent).result.then((newStrokes: string[]) => {
|
||||||
this.model[this.model.findIndex(x => x === item)] = value
|
this.hotkeys.find(hotkey => this.isEqual(hotkey, item))!.strokes = newStrokes
|
||||||
this.model = this.model.slice()
|
this.storeUpdatedHotkeys()
|
||||||
this.modelChange.emit(this.model)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
addItem (): void {
|
addItem (): void {
|
||||||
this.ngbModal.open(HotkeyInputModalComponent).result.then((value: string[]) => {
|
this.ngbModal.open(HotkeyInputModalComponent).result.then((value: string[]) => {
|
||||||
this.model = this.model.concat([value])
|
this.hotkeys.push({ strokes: value, isDuplicate: false })
|
||||||
this.modelChange.emit(this.model)
|
this.storeUpdatedHotkeys()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
removeItem (item: string[]): void {
|
removeItem (item: Hotkey): void {
|
||||||
this.model = this.model.filter(x => x !== item)
|
this.hotkeys = this.hotkeys.filter(x => x !== item)
|
||||||
this.modelChange.emit(this.model)
|
this.storeUpdatedHotkeys()
|
||||||
|
}
|
||||||
|
|
||||||
|
private storeUpdatedHotkeys () {
|
||||||
|
this.hotkeysChange.emit(this.hotkeys)
|
||||||
|
}
|
||||||
|
|
||||||
|
private isEqual (h: Hotkey, item: Hotkey) {
|
||||||
|
return JSON.stringify(h.strokes) === JSON.stringify(item.strokes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue