@elastic/ctags-langserver
Advanced tools
Comparing version 0.1.9 to 0.1.10
@@ -18,3 +18,3 @@ import { InitializeParams, InitializeResult, DidChangeWorkspaceFoldersParams, DocumentSymbolParams, TextDocumentPositionParams, Hover, Location, ReferenceParams, DocumentSymbol } from 'vscode-languageserver-protocol'; | ||
initialize(params: InitializeParams): Promise<InitializeResult>; | ||
didChangeWorkspaceFolders(params: DidChangeWorkspaceFoldersParams): void; | ||
didChangeWorkspaceFolders(params: DidChangeWorkspaceFoldersParams): Promise<void>; | ||
documentSymbol(params: DocumentSymbolParams): Promise<DocumentSymbol[]>; | ||
@@ -30,3 +30,5 @@ full(params: FullParams): Promise<Full>; | ||
private runCtagsOnSingleFile; | ||
private addSwiftSupport; | ||
private addKotlinSupport; | ||
protected findCtagsPath(): string; | ||
} |
@@ -41,2 +41,3 @@ "use strict"; | ||
'Iniconf', | ||
'Kotlin', | ||
'Lua', | ||
@@ -55,2 +56,3 @@ 'JSON', | ||
'SQL', | ||
'Swift', | ||
'Tcl', | ||
@@ -74,4 +76,9 @@ 'TypeScript', | ||
const rootPath = url_1.fileURLToPath(params.rootUri); | ||
this.runCtags(rootPath); | ||
this.rootPaths.push(rootPath); | ||
yield this.runCtags(rootPath); | ||
if (!fs_1.existsSync(path.resolve(rootPath, this.tagFileName))) { | ||
this.logger.error(`Fail to initialize ${params.rootUri}`); | ||
} | ||
else { | ||
this.rootPaths.push(rootPath); | ||
} | ||
this.initializeResult = { | ||
@@ -90,14 +97,21 @@ capabilities: { | ||
didChangeWorkspaceFolders(params) { | ||
const added = params.event.added; | ||
const removed = params.event.removed; | ||
added.forEach(add => { | ||
const rootPath = url_1.fileURLToPath(add.uri); | ||
this.runCtags(rootPath); | ||
this.rootPaths.push(rootPath); | ||
}); | ||
removed.forEach(remove => { | ||
const index = this.rootPaths.indexOf(url_1.fileURLToPath(remove.uri)); | ||
if (index !== -1) { | ||
this.rootPaths.splice(index, 1); | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const added = params.event.added; | ||
const removed = params.event.removed; | ||
for (const add of added) { | ||
const rootPath = url_1.fileURLToPath(add.uri); | ||
yield this.runCtags(rootPath); | ||
if (!fs_1.existsSync(path.resolve(rootPath, this.tagFileName))) { | ||
this.logger.error(`Fail to initialize ${add.uri}`); | ||
} | ||
else { | ||
this.rootPaths.push(rootPath); | ||
} | ||
} | ||
removed.forEach(remove => { | ||
const index = this.rootPaths.indexOf(url_1.fileURLToPath(remove.uri)); | ||
if (index !== -1) { | ||
this.rootPaths.splice(index, 1); | ||
} | ||
}); | ||
}); | ||
@@ -244,87 +258,93 @@ } | ||
const relativePath = path.relative(rootPath, filePath); | ||
this.runCtagsOnSingleFile(rootPath, relativePath); | ||
const stream = ctags.createReadStream(path.resolve(rootPath, this.tmpTagName)); | ||
return new Promise(resolve => { | ||
let results = []; | ||
// @ts-ignore | ||
stream.on('data', (tags) => { | ||
yield this.runCtagsOnSingleFile(rootPath, relativePath); | ||
if (!fs_1.existsSync(path.resolve(rootPath, this.tmpTagName))) { | ||
this.logger.error(`Fail to generate tags for ${unitURI}`); | ||
return []; | ||
} | ||
else { | ||
const stream = ctags.createReadStream(path.resolve(rootPath, this.tmpTagName)); | ||
return new Promise(resolve => { | ||
let results = []; | ||
// @ts-ignore | ||
for (let def of tags) { | ||
let symbolInformation = vscode_languageserver_protocol_1.SymbolInformation.create(def.name, vscode_languageserver_protocol_1.SymbolKind.Method, vscode_languageserver_protocol_1.Range.create(vscode_languageserver_protocol_1.Position.create(def.lineNumber - 1, 0), vscode_languageserver_protocol_1.Position.create(def.lineNumber - 1, 0)), unitURI, relativePath); | ||
if (def.fields !== undefined) { | ||
if (def.fields.struct) { | ||
symbolInformation.containerName = def.fields.struct; | ||
stream.on('data', (tags) => { | ||
// @ts-ignore | ||
for (let def of tags) { | ||
let symbolInformation = vscode_languageserver_protocol_1.SymbolInformation.create(def.name, vscode_languageserver_protocol_1.SymbolKind.Method, vscode_languageserver_protocol_1.Range.create(vscode_languageserver_protocol_1.Position.create(def.lineNumber - 1, 0), vscode_languageserver_protocol_1.Position.create(def.lineNumber - 1, 0)), unitURI, relativePath); | ||
if (def.fields !== undefined) { | ||
if (def.fields.struct) { | ||
symbolInformation.containerName = def.fields.struct; | ||
} | ||
else if (def.fields.class) { | ||
symbolInformation.containerName = def.fields.class; | ||
} | ||
else if (def.fields.interface) { | ||
symbolInformation.containerName = def.fields.interface; | ||
} | ||
else if (def.fields.function) { | ||
symbolInformation.containerName = def.fields.function; | ||
} | ||
else if (def.fields.enum) { | ||
symbolInformation.containerName = def.fields.enum; | ||
} | ||
else if (def.fields.namespace) { | ||
symbolInformation.containerName = def.fields.namespace; | ||
} | ||
else if (def.fields.module) { | ||
symbolInformation.containerName = def.fields.module; | ||
} | ||
} | ||
else if (def.fields.class) { | ||
symbolInformation.containerName = def.fields.class; | ||
switch (def.kind) { | ||
case 'namespace': | ||
symbolInformation.kind = vscode_languageserver_protocol_1.SymbolKind.Namespace; | ||
break; | ||
case 'package': | ||
symbolInformation.kind = vscode_languageserver_protocol_1.SymbolKind.Package; | ||
break; | ||
case 'module': | ||
symbolInformation.kind = vscode_languageserver_protocol_1.SymbolKind.Module; | ||
break; | ||
case 'variable': | ||
symbolInformation.kind = vscode_languageserver_protocol_1.SymbolKind.Variable; | ||
break; | ||
case 'function': | ||
symbolInformation.kind = vscode_languageserver_protocol_1.SymbolKind.Function; | ||
break; | ||
case 'class': | ||
symbolInformation.kind = vscode_languageserver_protocol_1.SymbolKind.Class; | ||
break; | ||
case 'field': | ||
symbolInformation.kind = vscode_languageserver_protocol_1.SymbolKind.Field; | ||
break; | ||
case 'method': | ||
symbolInformation.kind = vscode_languageserver_protocol_1.SymbolKind.Method; | ||
break; | ||
case 'struct': | ||
symbolInformation.kind = vscode_languageserver_protocol_1.SymbolKind.Struct; | ||
break; | ||
case 'enum': | ||
symbolInformation.kind = vscode_languageserver_protocol_1.SymbolKind.Enum; | ||
break; | ||
case 'enumerator': | ||
symbolInformation.kind = vscode_languageserver_protocol_1.SymbolKind.EnumMember; | ||
break; | ||
case 'member': | ||
symbolInformation.kind = vscode_languageserver_protocol_1.SymbolKind.Field; | ||
break; | ||
case 'typedef': | ||
symbolInformation.kind = vscode_languageserver_protocol_1.SymbolKind.Interface; | ||
break; | ||
case 'macro': | ||
symbolInformation.kind = vscode_languageserver_protocol_1.SymbolKind.Constant; | ||
break; | ||
default: | ||
break; | ||
} | ||
else if (def.fields.interface) { | ||
symbolInformation.containerName = def.fields.interface; | ||
} | ||
else if (def.fields.function) { | ||
symbolInformation.containerName = def.fields.function; | ||
} | ||
else if (def.fields.enum) { | ||
symbolInformation.containerName = def.fields.enum; | ||
} | ||
else if (def.fields.namespace) { | ||
symbolInformation.containerName = def.fields.namespace; | ||
} | ||
else if (def.fields.module) { | ||
symbolInformation.containerName = def.fields.module; | ||
} | ||
results.push(symbolInformation); | ||
} | ||
switch (def.kind) { | ||
case 'namespace': | ||
symbolInformation.kind = vscode_languageserver_protocol_1.SymbolKind.Namespace; | ||
break; | ||
case 'package': | ||
symbolInformation.kind = vscode_languageserver_protocol_1.SymbolKind.Package; | ||
break; | ||
case 'module': | ||
symbolInformation.kind = vscode_languageserver_protocol_1.SymbolKind.Module; | ||
break; | ||
case 'variable': | ||
symbolInformation.kind = vscode_languageserver_protocol_1.SymbolKind.Variable; | ||
break; | ||
case 'function': | ||
symbolInformation.kind = vscode_languageserver_protocol_1.SymbolKind.Function; | ||
break; | ||
case 'class': | ||
symbolInformation.kind = vscode_languageserver_protocol_1.SymbolKind.Class; | ||
break; | ||
case 'field': | ||
symbolInformation.kind = vscode_languageserver_protocol_1.SymbolKind.Field; | ||
break; | ||
case 'method': | ||
symbolInformation.kind = vscode_languageserver_protocol_1.SymbolKind.Method; | ||
break; | ||
case 'struct': | ||
symbolInformation.kind = vscode_languageserver_protocol_1.SymbolKind.Struct; | ||
break; | ||
case 'enum': | ||
symbolInformation.kind = vscode_languageserver_protocol_1.SymbolKind.Enum; | ||
break; | ||
case 'enumerator': | ||
symbolInformation.kind = vscode_languageserver_protocol_1.SymbolKind.EnumMember; | ||
break; | ||
case 'member': | ||
symbolInformation.kind = vscode_languageserver_protocol_1.SymbolKind.Field; | ||
break; | ||
case 'typedef': | ||
symbolInformation.kind = vscode_languageserver_protocol_1.SymbolKind.Interface; | ||
break; | ||
case 'macro': | ||
symbolInformation.kind = vscode_languageserver_protocol_1.SymbolKind.Constant; | ||
break; | ||
default: | ||
break; | ||
} | ||
results.push(symbolInformation); | ||
} | ||
}); | ||
stream.on('end', () => { | ||
resolve(results); | ||
}); | ||
}); | ||
stream.on('end', () => { | ||
resolve(results); | ||
}); | ||
}); | ||
} | ||
}); | ||
@@ -352,38 +372,55 @@ } | ||
runCtags(rootPath) { | ||
const ctagsPath = this.findCtagsPath(); | ||
const excludeCommands = utils_1.getGitIgnored(rootPath).map(pattern => `--exclude=${pattern}`).join(' '); | ||
try { | ||
child_process_1.execSync(`${ctagsPath} --fields=-anf+iKnS --languages=${CTAGS_SUPPORT_LANGS.join(',')} ${excludeCommands} -R`, { cwd: rootPath, stdio: 'pipe' }); | ||
} | ||
catch (err) { | ||
this.logger.error(`Fail to run ctags command with exit code ${err.status}`); | ||
this.logger.error(`${err.stderr}`); | ||
} | ||
try { | ||
if (!fs_1.existsSync(path.resolve(rootPath, this.tagFileName))) { | ||
this.logger.error(`Cannot find tag file in ${path.resolve(rootPath, this.tagFileName)}`); | ||
} | ||
} | ||
catch (err) { | ||
this.logger.error(err); | ||
} | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const params = [ | ||
'--links=no', | ||
'--fields=-anf+iKnS', | ||
`--languages=${CTAGS_SUPPORT_LANGS.join(',')}`, | ||
'-R', | ||
]; | ||
this.addKotlinSupport(params); | ||
this.addSwiftSupport(params); | ||
const p = child_process_1.spawn(this.findCtagsPath(), params, { cwd: rootPath, stdio: 'pipe' }); | ||
p.stderr.on('data', data => { | ||
this.logger.error(data.toString()); | ||
}); | ||
return new Promise((resolve) => { | ||
p.on('exit', () => resolve()); | ||
}); | ||
}); | ||
} | ||
runCtagsOnSingleFile(rootPath, filePath) { | ||
const ctagsPath = this.findCtagsPath(); | ||
try { | ||
child_process_1.execSync(`${ctagsPath} --fields=-anf+iKnS -f ${this.tmpTagName} ${filePath}`, { cwd: rootPath, stdio: 'pipe' }); | ||
const tmpTagsFile = path.resolve(rootPath, this.tmpTagName); | ||
if (fs_1.existsSync(tmpTagsFile)) { | ||
fs_1.unlinkSync(tmpTagsFile); | ||
} | ||
catch (err) { | ||
this.logger.error(`Fail to run ctags command with exit code ${err.status}`); | ||
this.logger.error(`${err.stderr}`); | ||
} | ||
try { | ||
if (!fs_1.existsSync(path.resolve(rootPath, this.tmpTagName))) { | ||
this.logger.error(`Cannot find tag file in ${path.resolve(rootPath, this.tmpTagName)}`); | ||
} | ||
} | ||
catch (err) { | ||
this.logger.error(err); | ||
} | ||
const params = [ | ||
'--links=no', | ||
'--fields=-anf+iKnS', | ||
'-f', | ||
this.tmpTagName, | ||
filePath, | ||
]; | ||
const p = child_process_1.spawn(this.findCtagsPath(), params, { cwd: rootPath, stdio: 'pipe' }); | ||
p.stderr.on('data', data => { | ||
this.logger.error(data.toString()); | ||
}); | ||
return new Promise((resolve) => { | ||
p.on('exit', () => resolve()); | ||
}); | ||
} | ||
// regex borrowed from https://github.com/oracle/opengrok/blob/master/opengrok-indexer/src/main/java/org/opengrok/indexer/analysis/Ctags.java | ||
addSwiftSupport(command) { | ||
command.unshift("--langdef=Swift", "--langmap=Swift:+.swift", "--regex-Swift=/enum[[:space:]]+([^\\{\\}]+).*$/\\1/n,enum,enums/", "--regex-Swift=/typealias[[:space:]]+([^:=]+).*$/\\1/t,typealias,typealiases/", "--regex-Swift=/struct[[:space:]]+([^:\\{]+).*$/\\1/s,struct,structs/", "--regex-Swift=/class[[:space:]]+([^:\\{]+).*$/\\1/c,class,classes/", "--regex-Swift=/func[[:space:]]+([^\\(\\)]+)\\([^\\(\\)]*\\)/\\1/f,function,functions/", "--regex-Swift=/(var|let)[[:space:]]+([^:=]+).*$/\\2/v,variable,variables/", "--regex-Swift=/^[[:space:]]*extension[[:space:]]+([^:\\{]+).*$/\\1/e,extension,extensions/"); | ||
} | ||
addKotlinSupport(command) { | ||
command.unshift("--langdef=Kotlin", "--langmap=Kotlin:+.kt", "--langmap=Kotlin:+.kts", | ||
// tslint:disable-next-line: max-line-length | ||
"--regex-Kotlin=/^[[:space:]]*((abstract|final|sealed|implicit|lazy)[[:space:]]*)*(private[^ ]*|protected)?[[:space:]]*class[[:space:]]+([[:alnum:]_:]+)/\\4/c,classes/", | ||
// tslint:disable-next-line: max-line-length | ||
"--regex-Kotlin=/^[[:space:]]*((abstract|final|sealed|implicit|lazy)[[:space:]]*)*(private[^ ]*|protected)?[[:space:]]*object[[:space:]]+([[:alnum:]_:]+)/\\4/o,objects/", | ||
// tslint:disable-next-line: max-line-length | ||
"--regex-Kotlin=/^[[:space:]]*((abstract|final|sealed|implicit|lazy)[[:space:]]*)*(private[^ ]*|protected)?[[:space:]]*((abstract|final|sealed|implicit|lazy)[[:space:]]*)*data class[[:space:]]+([[:alnum:]_:]+)/\\6/d,data classes/", | ||
// tslint:disable-next-line: max-line-length | ||
"--regex-Kotlin=/^[[:space:]]*((abstract|final|sealed|implicit|lazy)[[:space:]]*)*(private[^ ]*|protected)?[[:space:]]*interface[[:space:]]+([[:alnum:]_:]+)/\\4/i,interfaces/", "--regex-Kotlin=/^[[:space:]]*type[[:space:]]+([[:alnum:]_:]+)/\\1/T,types/", "--regex-Kotlin=/^[[:space:]]*((abstract|final|sealed|implicit|lazy|private[^ ]*(\\[[a-z]*\\])*|protected)[[:space:]]*)*fun[[:space:]]+([[:alnum:]_:]+)/\\4/m,methods/", "--regex-Kotlin=/^[[:space:]]*((abstract|final|sealed|implicit|lazy|private[^ ]*|protected)[[:space:]]*)*val[[:space:]]+([[:alnum:]_:]+)/\\3/C,constants/", "--regex-Kotlin=/^[[:space:]]*((abstract|final|sealed|implicit|lazy|private[^ ]*|protected)[[:space:]]*)*var[[:space:]]+([[:alnum:]_:]+)/\\3/v,variables/", "--regex-Kotlin=/^[[:space:]]*package[[:space:]]+([[:alnum:]_.:]+)/\\1/p,packages/", "--regex-Kotlin=/^[[:space:]]*import[[:space:]]+([[:alnum:]_.:]+)/\\1/I,imports/"); | ||
} | ||
findCtagsPath() { | ||
@@ -390,0 +427,0 @@ if (this.options.ctagsPath) { |
@@ -55,7 +55,7 @@ "use strict"; | ||
})); | ||
test('test didChangeWorkspaceFolders', () => { | ||
test('test didChangeWorkspaceFolders', () => __awaiter(this, void 0, void 0, function* () { | ||
const addedRootPath = fs.mkdtempSync(path.resolve(os.tmpdir(), 'ctags-langserver')); | ||
const addedSourceFilePath = path.resolve(addedRootPath, 'test.c'); | ||
fs.writeFileSync(addedSourceFilePath, content); | ||
lspServer.didChangeWorkspaceFolders({ | ||
yield lspServer.didChangeWorkspaceFolders({ | ||
event: { | ||
@@ -72,3 +72,3 @@ added: [ | ||
expect(fs.existsSync(path.resolve(addedRootPath, 'tags'))).toBe(true); | ||
}); | ||
})); | ||
test('test documentSymbol', () => __awaiter(this, void 0, void 0, function* () { | ||
@@ -75,0 +75,0 @@ const symbols = yield lspServer.documentSymbol({ |
{ | ||
"name": "@elastic/ctags-langserver", | ||
"version": "0.1.9", | ||
"version": "0.1.10", | ||
"description": "An all-languages language server built on top of ctags", | ||
@@ -5,0 +5,0 @@ "author": "Elastic", |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
15025723
1172