Skip to content

Commit 84f8cca

Browse files
committed
Many iprovements and fixes
1 parent 1699e93 commit 84f8cca

File tree

4 files changed

+92
-20
lines changed

4 files changed

+92
-20
lines changed

README.md

+16-1
Original file line numberDiff line numberDiff line change
@@ -154,13 +154,28 @@ Note how `exmap` lists command names without colons and in `nmap` the colon is r
154154
But first `<Space>` must be unbound with `unmap <Space>`.
155155
Afterwards `<Space>` can be mapped normally as any other key.
156156

157+
## Fixed Keyboard Layout in Normal Mode
158+
159+
In many languages and keyboard layouts it becomes problematic or plain impossible to use Vim keys.
160+
The Vim keys are located in different positions on some keyboard layouts, which could be confusing when switching
161+
layouts, and on some layouts (e.g. non-Western languages) the keys for Vim movements just don't exist.
162+
To be able to use Vim mode with those layouts & languages, you can turn on the "fixed keyboard layout" feature in the
163+
plugin settings.
164+
165+
When turned on for the first time, or when you click "capture current layout", your current keyboard layout is saved,
166+
and that will be the layout that is used when you are in Vim normal or visual mode.
167+
When you enter insert mode, you will type in your actual current system layout/language.
168+
169+
**This feature is experimental and may have unintended side-effects relating to Obsidian or editor shortcuts.**
170+
157171
## Changelog
158172

159-
### Not released yet
173+
### 0.4.0
160174
- `surround` and `pasteinto` commands (thanks @Andr3wD!)
161175
- Vim chord display (thanks @Andr3wD!)
162176
- Vim mode display (thanks @Andr3wD!)
163177
- Fixed [fold and unfold bug](https://github.com/esm7/obsidian-vimrc-support/issues/35).
178+
- The plugin now supports maintaining a fixed keyboard layout when in normal mode, if configured to do so.
164179

165180
### 0.3.1
166181

main.ts

+73-17
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,22 @@
11
import * as keyFromAccelerator from 'keyboardevent-from-electron-accelerator';
2-
import { App, MarkdownView, Plugin, PluginSettingTab, Setting, TFile } from 'obsidian';
2+
import { Notice, App, MarkdownView, Plugin, PluginSettingTab, Setting, TFile } from 'obsidian';
33

44
declare const CodeMirror: any;
55

66
interface Settings {
77
vimrcFileName: string,
88
displayChord: boolean,
9-
displayVimMode: boolean
9+
displayVimMode: boolean,
10+
fixedNormalModeLayout: boolean,
11+
capturedKeyboardMap: Record<string, string>
1012
}
1113

1214
const DEFAULT_SETTINGS: Settings = {
1315
vimrcFileName: ".obsidian.vimrc",
1416
displayChord: false,
15-
displayVimMode: false
17+
displayVimMode: false,
18+
fixedNormalModeLayout: false,
19+
capturedKeyboardMap: {}
1620
}
1721

1822
const enum vimStatus {
@@ -45,6 +49,26 @@ export default class VimrcPlugin extends Plugin {
4549
private currentVimStatus: vimStatus = vimStatus.normal;
4650
private customVimKeybinds: { [name: string]: boolean } = {};
4751
private currentSelection: CodeMirror.Range = null;
52+
private isInsertMode: boolean = false;
53+
54+
async captureKeyboardLayout() {
55+
// This is experimental API and it might break at some point:
56+
// https://developer.mozilla.org/en-US/docs/Web/API/KeyboardLayoutMap
57+
let keyMap: Record<string, string> = {};
58+
let layout = await (navigator as any).keyboard.getLayoutMap();
59+
let doneIterating = new Promise((resolve, reject) => {
60+
let counted = 0;
61+
layout.forEach((value: any, index: any) => {
62+
keyMap[index] = value;
63+
counted += 1;
64+
if (counted === layout.size)
65+
resolve();
66+
});
67+
});
68+
await doneIterating;
69+
new Notice('Keyboard layout captured');
70+
return keyMap;
71+
}
4872

4973
async onload() {
5074
console.log('loading Vimrc plugin');
@@ -59,11 +83,6 @@ export default class VimrcPlugin extends Plugin {
5983
catch(error => { console.log('Error loading vimrc file', VIMRC_FILE_NAME, 'from the vault root', error) });
6084
}));
6185

62-
// window.onkeydown = (ev: KeyboardEvent) => {
63-
// console.log('key = ', ev.key, 'code = ', ev.code);
64-
// ev.stopPropagation();
65-
// return false;
66-
// };
6786
this.registerDomEvent(document, 'click', () => {
6887
this.captureYankBuffer();
6988
});
@@ -105,6 +124,11 @@ export default class VimrcPlugin extends Plugin {
105124
this.defineSendKeys(CodeMirror.Vim);
106125
this.defineObCommand(CodeMirror.Vim);
107126
this.defineSurround(CodeMirror.Vim);
127+
this.defineFixedLayout();
128+
129+
CodeMirror.on(cmEditor, "vim-mode-change", (modeObj: any) => {
130+
this.isInsertMode = modeObj.mode === 'insert';
131+
});
108132

109133
// Record the position of selections
110134
CodeMirror.on(cmEditor, "cursorActivity", async (cm: any) => {
@@ -390,6 +414,21 @@ export default class VimrcPlugin extends Plugin {
390414
});
391415
}
392416
}
417+
418+
defineFixedLayout() {
419+
let cmEditor = this.getEditor(this.getActiveView());
420+
cmEditor.on('keydown', (instance: CodeMirror.Editor, ev: KeyboardEvent) => {
421+
if (this.settings.fixedNormalModeLayout) {
422+
const keyMap = this.settings.capturedKeyboardMap;
423+
if (!this.isInsertMode && !ev.shiftKey &&
424+
ev.code in keyMap && ev.key != keyMap[ev.code]) {
425+
CodeMirror.Vim.handleKey(instance, keyMap[ev.code], 'mapping');
426+
ev.preventDefault();
427+
return false;
428+
}
429+
}
430+
});
431+
}
393432
}
394433

395434
class SettingsTab extends PluginSettingTab {
@@ -412,10 +451,9 @@ class SettingsTab extends PluginSettingTab {
412451
.setDesc('Relative to vault directory (requires restart)')
413452
.addText((text) => {
414453
text.setPlaceholder(DEFAULT_SETTINGS.vimrcFileName);
415-
if (this.plugin.settings.vimrcFileName !== DEFAULT_SETTINGS.vimrcFileName)
416-
text.setValue(this.plugin.settings.vimrcFileName)
454+
text.setValue(this.plugin.settings.vimrcFileName || DEFAULT_SETTINGS.vimrcFileName);
417455
text.onChange(value => {
418-
this.plugin.settings.vimrcFileName = value || DEFAULT_SETTINGS.vimrcFileName;
456+
this.plugin.settings.vimrcFileName = value;
419457
this.plugin.saveSettings();
420458
})
421459
});
@@ -424,10 +462,9 @@ class SettingsTab extends PluginSettingTab {
424462
.setName('Vim chord display')
425463
.setDesc('Displays the current chord until completion. Ex: "<Space> f-" (requires restart)')
426464
.addToggle((toggle) => {
427-
if (this.plugin.settings.displayChord !== DEFAULT_SETTINGS.displayChord)
428-
toggle.setValue(this.plugin.settings.displayChord)
465+
toggle.setValue(this.plugin.settings.displayChord || DEFAULT_SETTINGS.displayChord);
429466
toggle.onChange(value => {
430-
this.plugin.settings.displayChord = value || DEFAULT_SETTINGS.displayChord;
467+
this.plugin.settings.displayChord = value;
431468
this.plugin.saveSettings();
432469
})
433470
});
@@ -436,12 +473,31 @@ class SettingsTab extends PluginSettingTab {
436473
.setName('Vim mode display')
437474
.setDesc('Displays the current vim mode (requires restart)')
438475
.addToggle((toggle) => {
439-
if (this.plugin.settings.displayVimMode !== DEFAULT_SETTINGS.displayVimMode)
440-
toggle.setValue(this.plugin.settings.displayVimMode)
476+
toggle.setValue(this.plugin.settings.displayVimMode || DEFAULT_SETTINGS.displayVimMode);
441477
toggle.onChange(value => {
442-
this.plugin.settings.displayVimMode = value || DEFAULT_SETTINGS.displayVimMode;
478+
this.plugin.settings.displayVimMode = value;
443479
this.plugin.saveSettings();
444480
})
445481
});
482+
483+
new Setting(containerEl)
484+
.setName('Use a fixed keyboard layout for Normal mode')
485+
.setDesc('Define a keyboard layout to always use when in Normal mode, regardless of the input language (experimental).')
486+
.addButton(async (button) => {
487+
button.setButtonText('Capture current layout');
488+
button.onClick(async () => {
489+
this.plugin.settings.capturedKeyboardMap = await this.plugin.captureKeyboardLayout();
490+
this.plugin.saveSettings();
491+
});
492+
})
493+
.addToggle((toggle) => {
494+
toggle.setValue(this.plugin.settings.fixedNormalModeLayout || DEFAULT_SETTINGS.fixedNormalModeLayout);
495+
toggle.onChange(async value => {
496+
this.plugin.settings.fixedNormalModeLayout = value;
497+
if (value && Object.keys(this.plugin.settings.capturedKeyboardMap).length === 0)
498+
this.plugin.settings.capturedKeyboardMap = await this.plugin.captureKeyboardLayout();
499+
this.plugin.saveSettings();
500+
});
501+
})
446502
}
447503
}

manifest.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"id": "obsidian-vimrc-support",
33
"name": "Vimrc Support",
4-
"version": "0.3.1",
4+
"version": "0.4.0",
55
"description": "Auto-load a startup file with Obsidian Vim commands.",
66
"author": "esm",
77
"authorUrl": "",

package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "obsidian-vimrc-support",
3-
"version": "0.3.1",
3+
"version": "0.4.0",
44
"description": "Auto-load a startup file with Obsidian Vim commands.",
55
"main": "main.js",
66
"scripts": {
@@ -15,6 +15,7 @@
1515
"@rollup/plugin-node-resolve": "^9.0.0",
1616
"@rollup/plugin-typescript": "^6.1.0",
1717
"@types/node": "^14.14.6",
18+
"codemirror": "^5.62.2",
1819
"keyboardevent-from-electron-accelerator": "*",
1920
"obsidian": "^0.12.11",
2021
"rollup": "^2.33.0",

0 commit comments

Comments
 (0)