UNPKG

fish-lsp

Version:

LSP implementation for fish/fish-shell

152 lines (151 loc) 5.55 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.isExportDefinition = isExportDefinition; exports.isExportVariableDefinitionName = isExportVariableDefinitionName; exports.findVariableDefinitionNameNode = findVariableDefinitionNameNode; exports.extractExportVariable = extractExportVariable; exports.buildExportDetail = buildExportDetail; exports.processExportCommand = processExportCommand; const vscode_languageserver_1 = require("vscode-languageserver"); const node_types_1 = require("../utils/node-types"); const symbol_1 = require("./symbol"); const definition_scope_1 = require("../utils/definition-scope"); const tree_sitter_1 = require("../utils/tree-sitter"); const markdown_builder_1 = require("../utils/markdown-builder"); const translation_1 = require("../utils/translation"); function isExportDefinition(node) { return (0, node_types_1.isCommandWithName)(node, 'export') && node.children.length >= 2; } function isExportVariableDefinitionName(node) { if ((0, node_types_1.isString)(node) || (0, node_types_1.isConcatenation)(node)) return false; if (!node.parent) return false; const isConcatenated = (0, node_types_1.isConcatenation)(node.parent); let parentNode = node.parent; if (isConcatenated) parentNode = parentNode.parent; if (!parentNode || !(0, node_types_1.isCommandWithName)(parentNode, 'export')) return false; const firstChild = isConcatenated ? parentNode.firstNamedChild : parentNode.firstChild; if (firstChild && firstChild.equals(node)) return false; const args = parentNode.childrenForFieldName('argument'); const exportName = isConcatenated ? args.at(0)?.firstChild : args.at(0); return !!exportName && exportName.equals(node); } function findVariableDefinitionNameNode(node) { function getName(node) { let current = node; while (current && current.type === 'concatenation') { current = current.firstChild; } if (!current) return undefined; return current; } function getValue(node) { let current = node; while (current && current.type === 'concatenation') { current = current.lastChild; } if (!current) return undefined; return current; } let isConcatenation = false; const nameNode = getName(node); const valueNode = getValue(node); const isValueString = !!valueNode && (0, node_types_1.isString)(valueNode); const isNonEscaped = !!valueNode && !!nameNode && nameNode.equals(valueNode); if (!nameNode || !valueNode) { return { nameNode, valueNode, isConcatenation: false, isValueString, isNonEscaped, }; } if (nameNode?.equals(valueNode)) { return { nameNode, valueNode, isConcatenation, isValueString, isNonEscaped, }; } isConcatenation = true; return { nameNode, valueNode, isConcatenation, isValueString, isNonEscaped, }; } function extractExportVariable(node) { const argument = node.firstChild?.nextNamedSibling; if (!argument) { return null; } const [name, ...valueParts] = argument.text.split('='); const value = valueParts.join('='); const nameStart = { line: argument.startPosition.row, character: argument.startPosition.column, }; const nameEnd = { line: nameStart.line, character: nameStart.character + name.length, }; return { name, value, nameRange: vscode_languageserver_1.Range.create(nameStart, nameEnd) }; } function buildExportDetail(doc, commandNode, variableDefinitionNode) { const commandText = commandNode.text; const extracted = extractExportVariable(variableDefinitionNode); if (!extracted) return ''; const { name, value } = extracted; const detail = [ `${markdown_builder_1.md.bold('(variable)')} ${markdown_builder_1.md.inlineCode(name)}`, `${markdown_builder_1.md.italic('globally')} scoped, ${markdown_builder_1.md.italic('exported')}`, `located in file: ${markdown_builder_1.md.inlineCode((0, translation_1.uriToReadablePath)(doc.uri))}`, markdown_builder_1.md.separator(), markdown_builder_1.md.codeBlock('fish', commandText), markdown_builder_1.md.separator(), markdown_builder_1.md.codeBlock('fish', `set -gx ${name} ${value}`), ].join(markdown_builder_1.md.newline()); return detail; } function processExportCommand(document, node, children = []) { if (!isExportDefinition(node)) return []; const found = findVariableDefinitionNameNode(node); const varDefNode = found?.nameNode; if (!found || !varDefNode) return []; const { name, nameRange, } = extractExportVariable(varDefNode); const scope = definition_scope_1.DefinitionScope.create(node.parent || node, 'global'); const detail = buildExportDetail(document, node, found.nameNode); return [ symbol_1.FishSymbol.fromObject({ name, node, focusedNode: varDefNode, range: (0, tree_sitter_1.getRange)(node), selectionRange: nameRange, fishKind: 'EXPORT', document, uri: document.uri, detail, scope, children, }), ]; }