;
36 |
37 | protected printJson(obj: JSONSchema7Type, format = false) {
38 | return JSON.stringify(obj, undefined, format ? ' ' : undefined);
39 | }
40 |
41 | protected printAsDetails(rows: Row[]) {
42 | const lines: string[] = [];
43 | rows.forEach((row) => {
44 | let hideLine = '';
45 | if (row.type) {
46 | hideLine += `Type: ${row.type}
`;
47 | }
48 | if (row.default !== undefined) {
49 | hideLine += 'Default: ';
50 | hideLine +=
51 | '' + this.printJson(row.default, true) + '
';
52 | }
53 | if (hideLine) {
54 | lines.push(``);
55 | }
56 | lines.push(
57 | `${row.name}
: ${row.description}.
`,
58 | );
59 | if (hideLine) {
60 | lines.push(hideLine);
61 | lines.push(' ');
62 | }
63 | });
64 | return lines;
65 | }
66 |
67 | /**
68 | * @deprecated
69 | */
70 | protected printAsList(rows: Row[]) {
71 | const lines: string[] = [];
72 | rows.forEach((row) => {
73 | let line = `- \`${row.name}\``;
74 | const descriptions: string[] = [];
75 | if (row.description) {
76 | descriptions.push(row.description);
77 | }
78 | if (row.type) {
79 | descriptions.push(`type: \`${this.printJson(row.type)}\``);
80 | }
81 | if (row.default !== undefined) {
82 | descriptions.push(`default: \`${this.printJson(row.default)}\``);
83 | }
84 | if (descriptions.length) {
85 | line += ': ' + descriptions.join(', ');
86 | }
87 | lines.push(line);
88 | });
89 | return lines;
90 | }
91 |
92 | async attach(headLevel: number, attachTitle: string, markdownPath: string) {
93 | const markdown = await fsp.readFile(markdownPath, 'utf8');
94 | const markdownLines = markdown.split('\n');
95 | let startIndex = markdownLines.findIndex((line) =>
96 | new RegExp('#'.repeat(headLevel) + '\\s*' + attachTitle + '\\s*').test(
97 | line,
98 | ),
99 | );
100 | if (startIndex < 0) {
101 | return;
102 | }
103 | startIndex += 1;
104 | const endIndex = markdownLines
105 | .slice(startIndex)
106 | .findIndex((line) => new RegExp(`#{1,${headLevel}}[^#]`).test(line));
107 | const removeCount = endIndex < 0 ? 0 : endIndex;
108 |
109 | const sections = await this.generate();
110 | const lines: string[] = ['', this.hint, this.ignorePrettierStart];
111 | for (const section of sections) {
112 | if (section.title) {
113 | lines.push(`${section.title}`);
114 | }
115 | lines.push(...this.printAsDetails(section.rows));
116 | }
117 | lines.push('');
118 | lines.push(this.ignorePrettierEnd);
119 | lines.push('');
120 | markdownLines.splice(startIndex, removeCount, ...lines);
121 | console.log(markdownLines.join('\n'))
122 | await fsp.writeFile(markdownPath, markdownLines.join('\n'));
123 | console.log(`Attached to ${attachTitle} header`);
124 | }
125 | }
126 |
127 | class ConfigurationDocGenerator extends DocGenerator {
128 | constructor(
129 | generateCommand: string,
130 | public packageDeclarationFilepath: string,
131 | ) {
132 | super(generateCommand);
133 | }
134 |
135 | isNodeExported(node: ts.Node) {
136 | return (
137 | (ts.getCombinedModifierFlags(node as ts.Declaration) &
138 | ts.ModifierFlags.Export) !==
139 | 0 ||
140 | (!!node.parent && node.parent.kind === ts.SyntaxKind.SourceFile)
141 | );
142 | }
143 |
144 | async generate() {
145 | const defRows: Row[] = [];
146 | const propRows: Row[] = [];
147 |
148 | const conf = Pkg.contributes.configuration;
149 | const title = conf.title;
150 | const filename = pathLib.basename(this.packageDeclarationFilepath);
151 |
152 | const Kind = ts.SyntaxKind;
153 | const prog = ts.createProgram([this.packageDeclarationFilepath], {
154 | strict: true,
155 | });
156 | const sourceFile = prog.getSourceFile(this.packageDeclarationFilepath)!;
157 | const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed });
158 | const checker = prog.getTypeChecker();
159 |
160 | function print(node: ts.Node): string {
161 | return printer.printNode(ts.EmitHint.Unspecified, node, sourceFile);
162 | }
163 |
164 | function debug(node: ts.Node) {
165 | console.log(Kind[node.kind]);
166 | console.log(print(node));
167 | }
168 |
169 | sourceFile.forEachChild((node) => {
170 | if (!this.isNodeExported(node)) {
171 | return;
172 | }
173 |
174 | if (ts.isTypeAliasDeclaration(node)) {
175 | defRows.push({
176 | name: node.name.text,
177 | description: node.name.text,
178 | type: print(node.type),
179 | });
180 | } else if (ts.isInterfaceDeclaration(node)) {
181 | if (node.name.text === title) {
182 | node.forEachChild((prop) => {
183 | if (!ts.isPropertySignature(prop)) {
184 | return;
185 | }
186 | const symbol = checker.getSymbolAtLocation(prop.name);
187 | if (!symbol) {
188 | return;
189 | }
190 |
191 | const name = symbol.getName();
192 | // @ts-ignore
193 | const jsonProp = conf.properties[name as any] as Definition & {
194 | default_doc?: string;
195 | };
196 | propRows.push({
197 | name,
198 | description: ts.displayPartsToString(
199 | symbol.getDocumentationComment(checker),
200 | ),
201 | type: prop.type ? print(prop.type) : undefined,
202 | default: jsonProp.default_doc
203 | ? jsonProp.default_doc
204 | : jsonProp.default,
205 | });
206 | });
207 | }
208 | } else {
209 | console.error(`[gen_doc] ${filename} not support ${print(node)}`);
210 | }
211 | });
212 |
213 | return [
214 | { title: 'Properties', rows: propRows },
215 | ];
216 | }
217 | }
218 |
219 | // class CommandDocGenerator extends DocGenerator {
220 | // async generate() {
221 | // const cmds = Pkg.contributes.commands as Cmd[];
222 | // const rows: Row[] = [];
223 | // cmds.forEach((cmd) => {
224 | // rows.push({
225 | // name: cmd.command,
226 | // description: cmd.title,
227 | // });
228 | // });
229 | // return [{ rows }];
230 | // }
231 | // }
232 |
233 | async function main() {
234 | const cmd = 'yarn run bulid:doc';
235 | const markdownPath = `${__dirname}/../README.md`
236 | const packageDeclarationFilepath = `${__dirname}/../src/types/pkg-config.d.ts`
237 | // await new CommandDocGenerator(cmd).attach(2, 'Commands', markdownPath);
238 | await new ConfigurationDocGenerator(cmd, packageDeclarationFilepath).attach(
239 | 2,
240 | 'Configuration',
241 | markdownPath
242 | );
243 | }
244 |
245 | main().catch(console.error);
246 |
--------------------------------------------------------------------------------
/scripts/readme.md:
--------------------------------------------------------------------------------
1 | Reference: https://github.com/weirongxu/coc-explorer/tree/master/scripts
2 |
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | import {
2 | Position,
3 | ProviderResult,
4 | TextDocument,
5 | ExtensionContext,
6 | CompletionItem,
7 | CompletionItemKind,
8 | CompletionItemProvider,
9 | languages,
10 | workspace,
11 | } from 'coc.nvim'
12 |
13 | export async function activate(context: ExtensionContext): Promise {
14 | const { subscriptions } = context
15 | const config = workspace.getConfiguration('just-complete')
16 |
17 | subscriptions.push(
18 | languages.registerCompletionItemProvider(
19 | 'coc-just-complete',
20 | config.get('shortcut'),
21 | null,
22 | new JustCompleteProvider(),
23 | ['_'],
24 | config.get('priority'),
25 | [],
26 | )
27 | )
28 | }
29 |
30 | export class JustCompleteProvider implements CompletionItemProvider {
31 | constructor() {}
32 |
33 | provideCompletionItems(document: TextDocument, position: Position): ProviderResult {
34 | const doc = workspace.getDocument(document.uri)
35 | if (!doc) return []
36 |
37 | const wordRange = doc.getWordRangeAtPosition(Position.create(position.line, position.character - 1))
38 | if (!wordRange) return []
39 |
40 | const preWord = document.getText(wordRange)
41 | if (preWord.indexOf('_') < 0) return []
42 |
43 | const prePreWord = preWord.slice(0, preWord.lastIndexOf('_'))
44 |
45 | return this.gatherWords()
46 | .filter(word =>
47 | word.indexOf(prePreWord) < 0 &&
48 | prePreWord.indexOf(word) < 0)
49 | .map(word => ({
50 | "label": `${prePreWord}_${word}`,
51 | "kind": CompletionItemKind.Text,
52 | "insertText": `${prePreWord}_${word}`
53 | }))
54 | }
55 |
56 | private gatherWords(): string[] {
57 | const words: string[] = []
58 | workspace.documents.forEach(document => {
59 | if (document['isIgnored']) return
60 | for (const word of document['words'] as string[]) {
61 | for (const word_no_underscore of word.split('_')) {
62 | if (!words.includes(word_no_underscore) && word_no_underscore.length >= 3) {
63 | words.push(word_no_underscore)
64 | }
65 | }
66 | }
67 | })
68 | return words
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/src/types/pkg-config.d.ts:
--------------------------------------------------------------------------------
1 | /* tslint:disable */
2 | /**
3 | * This file was automatically generated by json-schema-to-typescript.
4 | * DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file,
5 | * and run json-schema-to-typescript to regenerate this file.
6 | */
7 |
8 | export interface JustComplete {
9 | 'just-complete.shortcut'?: string;
10 | 'just-complete.priority'?: number;
11 | [k: string]: unknown;
12 | }
13 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./node_modules/@voldikss/tsconfig/tsconfig.json",
3 | "compilerOptions": {
4 | "declaration": false,
5 | "outDir": "lib",
6 | "target": "es2015",
7 | "module": "commonjs",
8 | "moduleResolution": "node",
9 | "lib": ["es2018"],
10 | "plugins": []
11 | },
12 | "include": ["src"],
13 | "exclude": []
14 | }
15 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | module.exports = {
4 | entry: './src/index.ts',
5 | target: 'node',
6 | mode: 'none',
7 | resolve: {
8 | mainFields: ['module', 'main'],
9 | extensions: ['.js', '.ts']
10 | },
11 | externals: {
12 | 'coc.nvim': 'commonjs coc.nvim'
13 | },
14 | module: {
15 | rules: [
16 | {
17 | test: /\.ts$/,
18 | exclude: /node_modules/,
19 | use: [
20 | {
21 | loader: 'ts-loader',
22 | options: {
23 | compilerOptions: {
24 | sourceMap: true
25 | }
26 | }
27 | }
28 | ]
29 | }
30 | ]
31 | },
32 | output: {
33 | path: path.join(__dirname, 'lib'),
34 | filename: 'index.js',
35 | libraryTarget: 'commonjs'
36 | },
37 | plugins: [],
38 | node: {
39 | __dirname: false,
40 | __filename: false
41 | }
42 | };
43 |
--------------------------------------------------------------------------------