mirror of
https://github.com/narrrl/narl-workspace.git
synced 2026-11-03 16:41:27 +01:00
fix: legible caret and working :q!
CodeMirror injects its own `.cm-cursor` rule after our stylesheet, so the equally specific override lost and the caret painted black on a dark background. Qualify the selector, same as `.cm-activeLine`. `:q!` reached the command table as the literal name `quit!`, which nothing matched. Commands now carry an optional `bang` variant, and `runCommand` splits a trailing `!` off any head before looking it up. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01476ZKdB4k3rPDwvVhXcnDg
This commit is contained in:
1 parent
e0565ea1b4
commit
bf3c1f547a
4 files changed
+31
-9
No files matched your search
+11
-2
@@ -198,11 +198,20 @@ input::placeholder { color: var(--fg-faint); }
|
|||||||
.cm-editor .cm-activeLine { background: color-mix(in srgb, var(--fg) 4%, transparent); }
|
.cm-editor .cm-activeLine { background: color-mix(in srgb, var(--fg) 4%, transparent); }
|
||||||
.cm-selectionBackground, .cm-content ::selection { background: var(--select) !important; }
|
.cm-selectionBackground, .cm-content ::selection { background: var(--select) !important; }
|
||||||
|
|
||||||
/* Insert mode: a 2px bar reads far better than the browser's hairline caret. */
|
/*
|
||||||
.cm-cursor, .cm-cursor-primary {
|
* Insert mode: a 2px bar reads far better than the browser's hairline caret.
|
||||||
|
* CodeMirror injects `.cm-cursor { border-left: 1.2px solid black }` after this
|
||||||
|
* stylesheet, so — like `.cm-activeLine` above — an equally specific selector
|
||||||
|
* loses and the caret renders black on a dark background. Qualify it to win.
|
||||||
|
*/
|
||||||
|
.cm-editor .cm-cursor,
|
||||||
|
.cm-editor .cm-cursor-primary,
|
||||||
|
.cm-editor .cm-dropCursor {
|
||||||
border-left: 2px solid var(--accent);
|
border-left: 2px solid var(--accent);
|
||||||
border-right: 0;
|
border-right: 0;
|
||||||
|
margin-left: -1px;
|
||||||
}
|
}
|
||||||
|
.cm-editor .cm-cursor-secondary { border-left-color: var(--accent-dim); }
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Normal mode: the vim plugin paints the character *inside* the block cursor,
|
* Normal mode: the vim plugin paints the character *inside* the block cursor,
|
||||||
|
|||||||
@@ -45,11 +45,12 @@
|
|||||||
for (const spec of commands) {
|
for (const spec of commands) {
|
||||||
const names = [spec.name, ...(spec.aliases ?? [])]
|
const names = [spec.name, ...(spec.aliases ?? [])]
|
||||||
for (const name of names) {
|
for (const name of names) {
|
||||||
if (name.includes('!')) continue
|
|
||||||
Vim.defineEx(name, name, (_cm: unknown, params: { argString?: string }) => {
|
Vim.defineEx(name, name, (_cm: unknown, params: { argString?: string }) => {
|
||||||
const arg = (params.argString ?? '').trim()
|
const arg = (params.argString ?? '').trim()
|
||||||
// vim parses `:q!` as command `q` with the bang left in the arguments.
|
// vim parses `:q!` as command `q` with the bang left in the arguments,
|
||||||
void runCommand(arg === '!' ? `${spec.name}!` : `${spec.name} ${arg}`)
|
// so put it back on the name before handing the line over.
|
||||||
|
const bang = arg.startsWith('!')
|
||||||
|
void runCommand(`${spec.name}${bang ? '!' : ''} ${bang ? arg.slice(1).trim() : arg}`)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,6 +46,10 @@
|
|||||||
{#if spec.args}<span class="faint"> {spec.args}</span>{/if}
|
{#if spec.args}<span class="faint"> {spec.args}</span>{/if}
|
||||||
</dt>
|
</dt>
|
||||||
<dd>{spec.help}</dd>
|
<dd>{spec.help}</dd>
|
||||||
|
{#if spec.bang}
|
||||||
|
<dt>:{spec.name}!{#if spec.aliases?.length}<span class="faint"> ({spec.aliases.map((a) => `${a}!`).join(' ')})</span>{/if}</dt>
|
||||||
|
<dd>{spec.bang.help}</dd>
|
||||||
|
{/if}
|
||||||
{/each}
|
{/each}
|
||||||
</dl>
|
</dl>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
+12
-4
@@ -16,6 +16,8 @@ export interface CommandSpec {
|
|||||||
args?: string
|
args?: string
|
||||||
help: string
|
help: string
|
||||||
run: (arg: string) => void | Promise<void>
|
run: (arg: string) => void | Promise<void>
|
||||||
|
/** The forcing variant, `:name!` — vim hands the bang over as an argument. */
|
||||||
|
bang?: { help: string; run: (arg: string) => void | Promise<void> }
|
||||||
}
|
}
|
||||||
|
|
||||||
const requireOpen = () => {
|
const requireOpen = () => {
|
||||||
@@ -59,9 +61,7 @@ export const commands: CommandSpec[] = [
|
|||||||
}
|
}
|
||||||
hooks.focusList()
|
hooks.focusList()
|
||||||
},
|
},
|
||||||
},
|
bang: {
|
||||||
{
|
|
||||||
name: 'q!',
|
|
||||||
help: 'discard changes and close the editor',
|
help: 'discard changes and close the editor',
|
||||||
run: async () => {
|
run: async () => {
|
||||||
const open = diary.open
|
const open = diary.open
|
||||||
@@ -71,6 +71,7 @@ export const commands: CommandSpec[] = [
|
|||||||
hooks.focusList()
|
hooks.focusList()
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: 'new',
|
name: 'new',
|
||||||
aliases: ['n', 'o'],
|
aliases: ['n', 'o'],
|
||||||
@@ -244,11 +245,18 @@ export async function runCommand(line: string): Promise<void> {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const spec = lookup.get(head)
|
// `:q!`, `:quit!` — the bang is part of the command name, not an argument.
|
||||||
|
const forced = head.endsWith('!')
|
||||||
|
const spec = lookup.get(forced ? head.slice(0, -1) : head)
|
||||||
if (!spec) {
|
if (!spec) {
|
||||||
diary.say(`E492: not an editor command: ${head}`, 'error')
|
diary.say(`E492: not an editor command: ${head}`, 'error')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if (forced) {
|
||||||
|
if (!spec.bang) return diary.say(`E477: no ! allowed: ${head}`, 'error')
|
||||||
|
await spec.bang.run(arg)
|
||||||
|
return
|
||||||
|
}
|
||||||
await spec.run(arg)
|
await spec.run(arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user