Open Mikestriken opened 3 months ago
I used generative AI (and referenced some of abrahamneben's code in his fork) to implement my feature request. The following was added to your code: Note: I used the source code of your last stable release to implement my code. in actions.ts:
export const select1LinesUp = (
editor: Editor,
selection: EditorSelection
) => {
let newHead: EditorPosition = {
line: selection.head.line - 1,
ch: selection.head.ch
};
// Ensure the new head position is within the bounds of the line
if (newHead.line >= 0) {
const lineAboveLength = editor.getLine(newHead.line).length;
if (newHead.ch > lineAboveLength) {
newHead.ch = lineAboveLength;
}
} else {
// Prevent moving the head above the first line
newHead.line = 0;
newHead.ch = 0;
}
return { anchor: selection.anchor, head: newHead };
};
export const select1LinesDown = (
editor: Editor,
selection: EditorSelection
) => {
let newHead: EditorPosition = {
line: selection.head.line + 1,
ch: selection.head.ch
};
// Ensure the new head position is within the bounds of the line
if (newHead.line < editor.lineCount()) {
const lineBelowLength = editor.getLine(newHead.line).length;
if (newHead.ch > lineBelowLength) {
newHead.ch = 0;
}
} else {
// Prevent moving the head below the last line
newHead.line = editor.lineCount() - 1;
newHead.ch = editor.getLine(newHead.line).length;
}
return { anchor: selection.anchor, head: newHead };
};
export const select1CharLeft = (
_editor: Editor,
selection: EditorSelection
) => {
const new_hd: EditorPosition = {
line:selection.head.line,
ch:selection.head.ch-1
};
return { anchor: selection.anchor, head: new_hd };
};
export const select1CharRight = (
_editor: Editor,
selection: EditorSelection
) => {
const new_hd: EditorPosition = {
line:selection.head.line,
ch:selection.head.ch+1
};
return { anchor: selection.anchor, head: new_hd };
};
// Define a reusable variable for punctuation characters
const punctuationChars = /[\s.,!?;:-_]/;
export const select1WordLeft = (
editor: Editor,
selection: EditorSelection
) => {
const { anchor, head } = selection; // Destructure the anchor and head positions from the selection
const line = editor.getLine(head.line); // Get the text of the line where the head is currently located
let newHead = { ...head }; // Create a new position object for the head to track the updated cursor position
// Handle the case where the cursor is at the beginning of the line and needs to move to the previous line
if (head.ch === 0 && head.line > 0) {
newHead.line--; // Move up one line
newHead.ch = editor.getLine(newHead.line).length; // Set the cursor to the end of the previous line
} else {
// Move left to the end of the next word or punctuation group
let ch = head.ch;
if (ch > 0 && !/[\s]/.test(line[ch-1]) && !punctuationChars.test(line[ch-1])) {
// If the character is part of a word, move left until the end of the word is found
while (ch > 0 && !/[\s]/.test(line[ch-1]) && !punctuationChars.test(line[ch-1])) ch--;
} else if (ch > 0 && punctuationChars.test(line[ch-1])) {
// If the character is a punctuation mark, move left until the end of the punctuation group is found
while (ch > 0 && punctuationChars.test(line[ch-1])) ch--;
} else {
ch--; // If none of the above, simply move one character to the left
}
newHead.ch = ch; // Update the head position with the new character position
}
// Adjust selection based on direction
if (editor.posToOffset(newHead) < editor.posToOffset(anchor)) {
// If the new head position is before the anchor, expand the selection to the left
return { anchor, head: newHead };
} else if (editor.posToOffset(newHead) > editor.posToOffset(anchor) && head.ch !== anchor.ch) {
// If the new head position is after the anchor and the selection is non-collapsed, shrink the selection from the right
return { anchor, head: newHead };
} else {
// If neither condition is met, maintain the current selection
return { anchor: newHead, head: anchor };
}
};
export const select1WordRight = (
editor: Editor,
selection: EditorSelection
) => {
const { anchor, head } = selection;
const line = editor.getLine(head.line);
let newHead = { ...head };
// Handle moving across lines
if (head.ch === line.length && head.line < editor.lineCount() - 1) {
newHead.line++;
newHead.ch = 0;
} else {
// Move right to the end of the next word or punctuation group
let ch = head.ch;
if (ch < line.length && !/[\s]/.test(line[ch]) && !punctuationChars.test(line[ch])) {
while (ch < line.length && !/[\s]/.test(line[ch]) && !punctuationChars.test(line[ch])) ch++;
} else if (ch < line.length && punctuationChars.test(line[ch])) {
while (ch < line.length && punctuationChars.test(line[ch])) ch++;
} else {
ch++;
}
newHead.ch = ch;
}
// Determine if we should shrink or expand the selection
if (editor.posToOffset(newHead) > editor.posToOffset(head)) {
// Shrink the selection from the left
return { anchor, head: newHead };
} else {
// Expand the selection to the right
return { anchor: newHead, head: anchor };
}
};
in main.ts
import {
// ...
select1LinesUp,
select1LinesDown,
select1CharLeft,
select1CharRight,
select1WordLeft,
select1WordRight,
// ...
} from './actions';
// ...
export default class CodeEditorShortcuts extends Plugin {
settings: PluginSettings;
async onload() {
await this.loadSettings();
// ...
this.addCommand({
id: 'select1LinesUp',
name: 'Select 1 lines up',
editorCallback: (editor) => withMultipleSelections(editor, select1LinesUp),
});
this.addCommand({
id: 'select1LinesDown',
name: 'Select 1 lines Down',
editorCallback: (editor) => withMultipleSelections(editor, select1LinesDown),
});
this.addCommand({
id: 'select1CharLeft',
name: 'Select 1 character left',
editorCallback: (editor) => withMultipleSelections(editor, select1CharLeft),
});
this.addCommand({
id: 'select1CharRight',
name: 'Select 1 character right',
editorCallback: (editor) => withMultipleSelections(editor, select1CharRight),
});
this.addCommand({
id: 'select1WordLeft',
name: 'Select 1 word left',
editorCallback: (editor) => withMultipleSelections(editor, select1WordLeft),
});
this.addCommand({
id: 'select1WordRight',
name: 'Select 1 word right',
editorCallback: (editor) => withMultipleSelections(editor, select1WordRight),
});
// ...
}
Known Bugs:
select1LineUp and
select1LineDown` in the case where a long line of text is present that has been word wrapped by the editor will not select the word wrapped line above, instead it will select the next line past the word wrapping.Additional Feature I would like implemented, word part detection;
IE: camelCase = 2 words not 1.
VSCode allows users to adjust the following:
Please add these key bindings as well!
I use alt + j / k /l / i as my arrow keys alt + o / u as word part left / right
and then just by pressing shift while using any of the above I move the cursor and select what's in between.