Skip to content

Commit

Permalink
refactor: Simplify stateField type
Browse files Browse the repository at this point in the history
Fixes #20
  • Loading branch information
tmcw committed Apr 4, 2024
1 parent 7dad950 commit 8358456
Show file tree
Hide file tree
Showing 5 changed files with 36 additions and 56 deletions.
10 changes: 4 additions & 6 deletions src/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,8 @@ export function acceptSuggestionCommand(view: EditorView) {
// We delete the ghost text and insert the suggestion.
// We also set the cursor to the end of the suggestion.
const stateField = view.state.field(completionDecoration)!;
const ghostTexts = stateField.ghostTexts;

if (!ghostTexts) {
if (!stateField) {
return false;
}

Expand Down Expand Up @@ -51,9 +50,8 @@ export function acceptSuggestionCommand(view: EditorView) {
export function rejectSuggestionCommand(view: EditorView) {
// We delete the suggestion, then carry through with the original keypress
const stateField = view.state.field(completionDecoration)!;
const ghostTexts = stateField.ghostTexts;

if (!ghostTexts?.length) {
if (!stateField) {
return false;
}

Expand All @@ -76,9 +74,9 @@ export function rejectSuggestionCommand(view: EditorView) {
// TODO: this isn't full reimplemented yet.
export function sameKeyCommand(view: EditorView, key: string) {
// When we type a key that is the same as the first letter of the suggestion, we delete the first letter of the suggestion and carry through with the original keypress
const ghostTexts = view.state.field(completionDecoration)!.ghostTexts;
const stateField = view.state.field(completionDecoration);

if (!ghostTexts || !ghostTexts.length) {
if (!stateField) {
return false;
}

Expand Down
36 changes: 6 additions & 30 deletions src/completionDecoration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,24 +11,18 @@ const ghostMark = Decoration.mark({ class: "cm-ghostText" });

export const completionDecoration = StateField.define<CompletionState>({
create(_state: EditorState) {
return { ghostTexts: null };
return null;
},
update(state: CompletionState, transaction: Transaction) {
for (const effect of transaction.effects) {
if (effect.is(addSuggestions)) {
// NOTE: here we're adjusting the decoration range
// to refer to locations in the document _after_ we've
// inserted the text.
let decorationOffset = 0;
const decorations = Decoration.set(
effect.value.suggestions.map((suggestion) => {
const endGhostText =
suggestion.startPos + suggestion.displayText.length;
let range = ghostMark.range(
decorationOffset + suggestion.startPos,
decorationOffset + endGhostText,
);
decorationOffset += suggestion.displayText.length;
console.log(suggestion.startPos, suggestion.endPos);
let range = ghostMark.range(suggestion.startPos, suggestion.endPos);
return range;
}),
);
Expand All @@ -37,36 +31,18 @@ export const completionDecoration = StateField.define<CompletionState>({
return {
decorations,
reverseChangeSet: effect.value.reverseChangeSet,
ghostTexts: effect.value.suggestions.map((suggestion) => {
const endGhostText =
suggestion.cursorPos + suggestion.displayText.length;
return {
text: suggestion.text,
displayText: suggestion.text,
startPos: suggestion.startPos,
endPos: suggestion.endPos,
decorations,
// TODO: what's the difference between this
// and startPos?
displayPos: suggestion.cursorPos,
endReplacement: suggestion.endReplacement,
endGhostText,
};
}),
};
} else if (effect.is(acceptSuggestion)) {
if (state.ghostTexts) {
return { ghostTexts: null };
}
return null;
} else if (effect.is(clearSuggestion)) {
return { ghostTexts: null };
return null;
}
}

return state;
},
provide: (field) =>
EditorView.decorations.from(field, (value) => {
return value.decorations || Decoration.none;
return value?.decorations || Decoration.none;
}),
});
26 changes: 17 additions & 9 deletions src/completionRequester.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ function shouldIgnoreUpdate(update: ViewUpdate) {
if (!update.view.hasFocus) return true;

// contains ghost text
if (update.state.field(completionDecoration).ghostTexts != null) return true;
if (update.state.field(completionDecoration)) return true;

// is autocompleting
if (completionStatus(update.state) === "active") return true;
Expand Down Expand Up @@ -121,18 +121,26 @@ export function completionRequester() {

const reverseChangeSet = insertChangeSet.invert(state.doc);

let combinedOffset = 0;
update.view.dispatch({
changes: insertChangeSet,
effects: addSuggestions.of({
reverseChangeSet,
suggestions: simplifyCompletions(completionResult).map((part) => ({
displayText: part.text,
endReplacement: 0, // "",
text: part.text,
cursorPos: pos,
startPos: Number(part.offset),
endPos: Number(part.offset) + part.text.length,
})),
suggestions: simplifyCompletions(completionResult).map((part) => {
try {
return {
displayText: part.text,
endReplacement: 0, // "",
text: part.text,
cursorPos: pos,
startPos: combinedOffset + Number(part.offset),
endPos:
combinedOffset + Number(part.offset) + part.text.length,
};
} finally {
combinedOffset += part.text.length;
}
}),
}),
annotations: [
copilotIgnore.of(null),
Expand Down
11 changes: 5 additions & 6 deletions src/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,11 @@ import { copilotIgnore } from "./annotations.js";
function isDecorationClicked(view: EditorView) {
let inRange = false;
const head = view.state.selection.asSingle().ranges.at(0)?.head;
if (head !== undefined) {
view.state
.field(completionDecoration)
.decorations?.between(head, head, () => {
inRange = true;
});
const stateField = view.state.field(completionDecoration);
if (head !== undefined && stateField) {
stateField.decorations?.between(head, head, () => {
inRange = true;
});
return inRange;
}
return false;
Expand Down
9 changes: 4 additions & 5 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,10 @@ export interface Suggestion {
endReplacement: number;
}

export interface CompletionState {
ghostTexts: GhostText[] | null;
reverseChangeSet?: ChangeSet;
decorations?: DecorationSet;
}
export type CompletionState = null | {
reverseChangeSet: ChangeSet;
decorations: DecorationSet;
};

export interface GhostText {
text: string;
Expand Down

0 comments on commit 8358456

Please sign in to comment.