Skip to content

Commit 763618c

Browse files
Kapil Borledaviwil
Kapil Borle
authored andcommitted
Componentize HelpCompletion feature
1 parent c5127d4 commit 763618c

File tree

1 file changed

+120
-63
lines changed

1 file changed

+120
-63
lines changed

src/features/HelpCompletion.ts

+120-63
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*--------------------------------------------------------*/
44

55
import { IFeature } from "../feature";
6-
import { TextDocumentChangeEvent, workspace, Disposable, Position, window, Range, EndOfLine, SnippetString } from "vscode";
6+
import { TextDocumentChangeEvent, workspace, Disposable, Position, window, Range, EndOfLine, SnippetString, TextDocument } from "vscode";
77
import { LanguageClient, RequestType } from "vscode-languageclient";
88

99
export namespace CommentHelpRequest {
@@ -23,98 +23,155 @@ interface CommentHelpRequestResult {
2323
enum SearchState { Searching, Locked, Found };
2424

2525
export class HelpCompletionFeature implements IFeature {
26-
private readonly triggerCharactersBlockComment: string;
27-
private readonly triggerCharactersLineComment: string;
28-
private triggerCharactersFound: string;
26+
private helpCompletionProvider: HelpCompletionProvider;
2927
private languageClient: LanguageClient;
3028
private disposable: Disposable;
31-
private searchState: SearchState;
32-
private get isBlockComment(): boolean {
33-
return this.triggerCharactersFound !== undefined &&
34-
this.triggerCharactersFound === this.triggerCharactersBlockComment;
35-
}
3629

3730
constructor() {
38-
this.triggerCharactersBlockComment = "<#";
39-
this.triggerCharactersLineComment = "##";
31+
this.helpCompletionProvider = new HelpCompletionProvider();
4032
let subscriptions = [];
4133
workspace.onDidChangeTextDocument(this.onEvent, this, subscriptions);
42-
this.searchState = SearchState.Searching;
4334
this.disposable = Disposable.from(...subscriptions);
4435
}
4536

4637
setLanguageClient(languageClient: LanguageClient) {
4738
this.languageClient = languageClient;
39+
this.helpCompletionProvider.languageClient = languageClient;
4840
}
4941

5042
dispose() {
5143
this.disposable.dispose();
5244
}
5345

5446
onEvent(changeEvent: TextDocumentChangeEvent): void {
55-
// todo split this method into logical components
56-
// todo create a helpcompletion provider class
57-
// todo associate state with a given document
58-
let text = changeEvent.contentChanges[0].text;
59-
switch (this.searchState) {
47+
this.helpCompletionProvider.updateState(
48+
changeEvent.document,
49+
changeEvent.contentChanges[0].text,
50+
changeEvent.contentChanges[0].range);
51+
52+
// todo raise an event when trigger is found, and attach complete() to the event.
53+
if (this.helpCompletionProvider.triggerFound) {
54+
this.helpCompletionProvider.reset();
55+
this.helpCompletionProvider.complete();
56+
}
57+
58+
}
59+
}
60+
61+
class TriggerFinder {
62+
private state: SearchState;
63+
private document: TextDocument;
64+
private count: number;
65+
constructor(private triggerCharacters: string) {
66+
this.state = SearchState.Searching;
67+
this.count = 0;
68+
}
69+
70+
public get found(): boolean {
71+
return this.state === SearchState.Found;
72+
}
73+
74+
public updateState(document: TextDocument, changeText: string): void {
75+
switch (this.state) {
6076
case SearchState.Searching:
61-
if (text.length === 1) {
62-
if (text[0] === this.triggerCharactersBlockComment[0]) {
63-
this.searchState = SearchState.Locked;
64-
this.triggerCharactersFound = this.triggerCharactersBlockComment;
65-
}
66-
else if (text[0] === this.triggerCharactersLineComment[0]) {
67-
this.searchState = SearchState.Locked;
68-
this.triggerCharactersFound = this.triggerCharactersLineComment;
69-
}
77+
if (changeText.length === 1 && changeText[0] === this.triggerCharacters[this.count]) {
78+
this.state = SearchState.Locked;
79+
this.document = document;
80+
this.count++;
7081
}
7182
break;
7283

7384
case SearchState.Locked:
74-
if (text.length === 1 && text[0] === this.triggerCharactersFound[1]) {
75-
this.searchState = SearchState.Found;
85+
if (changeText.length === 1 && changeText[0] === this.triggerCharacters[this.count] && document === this.document) {
86+
this.count++;
87+
if (this.count === this.triggerCharacters.length) {
88+
this.state = SearchState.Found;
89+
}
7690
}
7791
else {
78-
this.searchState = SearchState.Searching;
92+
this.reset();
7993
}
8094
break;
95+
96+
default:
97+
this.reset();
98+
break;
8199
}
100+
}
101+
102+
public reset(): void {
103+
this.state = SearchState.Searching;
104+
this.count = 0;
105+
}
106+
}
82107

83-
let r = changeEvent.contentChanges[0].range;
84-
console.log(`Search State: ${this.searchState.toString()}; Range: (${r.start.line}, ${r.start.character}), (${r.end.line}, ${r.end.character})`);
85-
if (this.searchState === SearchState.Found) {
86-
this.searchState = SearchState.Searching;
87-
if (this.languageClient) {
88-
let change = changeEvent.contentChanges[0];
89-
let triggerStartPos = change.range.start;
90-
let triggerEndPos = change.range.end;
91-
let doc = changeEvent.document;
92-
this.languageClient.sendRequest(
93-
CommentHelpRequest.type,
94-
{
95-
documentUri: changeEvent.document.uri.toString(),
96-
triggerPosition: triggerStartPos,
97-
blockComment: this.isBlockComment
98-
}).then(result => {
99-
if (result === undefined) {
100-
return;
101-
}
102-
103-
let content = result.content;
104-
if (content === undefined) {
105-
return;
106-
}
107-
108-
// todo add indentation level to the help content
109-
let editor = window.activeTextEditor;
110-
let replaceRange = new Range(triggerStartPos.translate(0, -1), triggerStartPos.translate(0, 1));
111-
112-
// Trim the last empty line and join the strings.
113-
let text = content.slice(0, -1).join(this.getEOL(doc.eol));
114-
editor.insertSnippet(new SnippetString(text), replaceRange);
115-
});
116-
}
108+
class HelpCompletionProvider {
109+
private triggerFinderBlockComment: TriggerFinder;
110+
private triggerFinderLineComment: TriggerFinder;
111+
private lastChangeText: string;
112+
private lastChangeRange: Range;
113+
private lastDocument: TextDocument;
114+
private langClient: LanguageClient;
115+
116+
constructor() {
117+
this.triggerFinderBlockComment = new TriggerFinder("<#");
118+
this.triggerFinderLineComment = new TriggerFinder("##");
119+
}
120+
121+
public get triggerFound(): boolean {
122+
return this.triggerFinderBlockComment.found || this.triggerFinderLineComment.found;
123+
}
124+
125+
public set languageClient(value: LanguageClient) {
126+
this.langClient = value;
127+
}
128+
129+
public updateState(document: TextDocument, changeText: string, changeRange: Range): void {
130+
this.lastDocument = document;
131+
this.lastChangeText = changeText;
132+
this.lastChangeRange = changeRange;
133+
this.triggerFinderBlockComment.updateState(document, changeText);
134+
this.triggerFinderLineComment.updateState(document, changeText);
135+
}
136+
137+
public reset(): void {
138+
this.triggerFinderBlockComment.reset();
139+
this.triggerFinderLineComment.reset();
140+
}
141+
142+
public complete(): Thenable<void> {
143+
if (this.langClient === undefined) {
144+
return;
117145
}
146+
147+
let change = this.lastChangeText;
148+
let triggerStartPos = this.lastChangeRange.start;
149+
let triggerEndPos = this.lastChangeRange.end;
150+
let doc = this.lastDocument;
151+
this.langClient.sendRequest(
152+
CommentHelpRequest.type,
153+
{
154+
documentUri: doc.uri.toString(),
155+
triggerPosition: triggerStartPos,
156+
blockComment: this.triggerFinderBlockComment.found
157+
}).then(result => {
158+
if (result === undefined) {
159+
return;
160+
}
161+
162+
let content = result.content;
163+
if (content === undefined) {
164+
return;
165+
}
166+
167+
// todo add indentation level to the help content
168+
let editor = window.activeTextEditor;
169+
let replaceRange = new Range(triggerStartPos.translate(0, -1), triggerStartPos.translate(0, 1));
170+
171+
// Trim the last empty line and join the strings.
172+
let text = content.slice(0, -1).join(this.getEOL(doc.eol));
173+
editor.insertSnippet(new SnippetString(text), replaceRange);
174+
});
118175
}
119176

120177
private getEOL(eol: EndOfLine): string {

0 commit comments

Comments
 (0)