UNPKG

fish-lsp

Version:

LSP implementation for fish/fish-shell

150 lines (149 loc) 8.05 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.FunctionEventOptions = exports.FunctionOptions = void 0; exports.findFunctionDefinitionChildren = findFunctionDefinitionChildren; exports.processArgvDefinition = processArgvDefinition; exports.isFunctionDefinitionName = isFunctionDefinitionName; exports.isFunctionVariableDefinitionName = isFunctionVariableDefinitionName; exports.findFunctionOptionNamedArguments = findFunctionOptionNamedArguments; exports.processFunctionDefinition = processFunctionDefinition; const options_1 = require("./options"); const symbol_1 = require("./symbol"); const node_types_1 = require("../utils/node-types"); const snippets_1 = require("../utils/snippets"); const definition_scope_1 = require("../utils/definition-scope"); const translation_1 = require("../utils/translation"); const tree_sitter_1 = require("../utils/tree-sitter"); const markdown_builder_1 = require("../utils/markdown-builder"); const symbol_kinds_1 = require("./symbol-kinds"); exports.FunctionOptions = [ options_1.Option.create('-a', '--argument-names').withMultipleValues(), options_1.Option.create('-d', '--description').withValue(), options_1.Option.create('-w', '--wraps').withValue(), options_1.Option.create('-e', '--on-event').withValue(), options_1.Option.create('-v', '--on-variable').withValue(), options_1.Option.create('-j', '--on-job-exit').withValue(), options_1.Option.create('-p', '--on-process-exit').withValue(), options_1.Option.create('-s', '--on-signal').withValue(), options_1.Option.create('-S', '--no-scope-shadowing'), options_1.Option.create('-V', '--inherit-variable').withValue(), ]; exports.FunctionEventOptions = [ options_1.Option.create('-e', '--on-event').withValue(), options_1.Option.create('-v', '--on-variable').withValue(), options_1.Option.create('-j', '--on-job-exit').withValue(), options_1.Option.create('-p', '--on-process-exit').withValue(), options_1.Option.create('-s', '--on-signal').withValue(), ]; function isFunctionDefinition(node) { return node.type === 'function_definition'; } function findFunctionDefinitionChildren(node) { return node.childrenForFieldName('option').filter(n => !(0, node_types_1.isEscapeSequence)(n) && !(0, node_types_1.isNewline)(n)); } function processArgvDefinition(document, node) { if (!document.isAutoloaded() && node.type === 'program') { return [ symbol_1.FishSymbol.fromObject({ name: 'argv', node: node, focusedNode: node.firstChild, fishKind: symbol_kinds_1.FishSymbolKindMap.variable, document, uri: document.uri, detail: snippets_1.PrebuiltDocumentationMap.getByName('argv').pop()?.description || 'the list of arguments passed to the function', scope: definition_scope_1.DefinitionScope.create(node, 'local'), selectionRange: { start: { line: 0, character: 0 }, end: { line: 0, character: 0 }, }, range: (0, tree_sitter_1.getRange)(node), children: [], }), ]; } return []; } function isFunctionDefinitionName(node) { if (!node.parent || !isFunctionDefinition(node.parent)) return false; return !!node.parent.firstNamedChild && node.parent.firstNamedChild.equals(node); } function isFunctionVariableDefinitionName(node) { if (!node.parent || !isFunctionDefinition(node.parent)) return false; const { variableNodes } = findFunctionOptionNamedArguments(node.parent); const definitionNode = variableNodes.find(n => n.equals(node)); return !!definitionNode && definitionNode.equals(node); } function findFunctionOptionNamedArguments(node) { const variableNodes = []; const eventNodes = []; const focused = node.childrenForFieldName('option').filter(n => !(0, node_types_1.isEscapeSequence)(n) && !(0, node_types_1.isNewline)(n)); const flagsSet = (0, options_1.findOptionsSet)(focused, exports.FunctionOptions); for (const flag of flagsSet) { const { option, value: focused } = flag; switch (true) { case option.isOption('-a', '--argument-names'): case option.isOption('-V', '--inherit-variable'): variableNodes.push(focused); break; case option.isOption('-e', '--on-event'): eventNodes.push(focused); break; default: break; } } return { variableNodes, eventNodes, flagsSet, }; } function processFunctionDefinition(document, node, children = []) { if (!isFunctionDefinition(node)) return []; const autoloadScope = (0, translation_1.isAutoloadedUriLoadsFunctionName)(document); const focusedNode = node.firstNamedChild; const isGlobal = autoloadScope(focusedNode) ? 'global' : 'local'; if (!focusedNode) return []; const functionSymbol = symbol_1.FishSymbol.create(focusedNode.text, node, focusedNode, symbol_kinds_1.FishSymbolKindMap.function, document, document.uri, node.text, definition_scope_1.DefinitionScope.create(node.parent, isGlobal)); const focused = node.childrenForFieldName('option').filter(n => !(0, node_types_1.isEscapeSequence)(n) && !(0, node_types_1.isNewline)(n)); functionSymbol.addChildren(symbol_1.FishSymbol.create('argv', node, node.firstNamedChild, symbol_kinds_1.FishSymbolKindMap.function_variable, document, document.uri, snippets_1.PrebuiltDocumentationMap.getByName('argv').pop()?.description || 'the list of arguments passed to the function', definition_scope_1.DefinitionScope.create(node, 'local'))); if (!focused) return [functionSymbol]; const { flagsSet } = findFunctionOptionNamedArguments(node); for (const flag of flagsSet) { const { option, value: focused } = flag; switch (true) { case option.isOption('-a', '--argument-names'): case option.isOption('-V', '--inherit-variable'): functionSymbol.addChildren(symbol_1.FishSymbol.create(focused.text, node, focused, symbol_kinds_1.FishSymbolKindMap.function_variable, document, document.uri, focused.text, definition_scope_1.DefinitionScope.create(node, 'local'))); break; case option.isOption('-e', '--on-event'): functionSymbol.addChildren(symbol_1.FishSymbol.create(focused.text, node, focused, symbol_kinds_1.FishSymbolKindMap.function_event, document, document.uri, [ `${markdown_builder_1.md.boldItalic('Generic Event:')} ${markdown_builder_1.md.inlineCode(focused.text)}`, `${markdown_builder_1.md.boldItalic('Event Handler:')} ${markdown_builder_1.md.inlineCode(focusedNode.text)}`, markdown_builder_1.md.separator(), markdown_builder_1.md.codeBlock('fish', [ `### function definition: '${focusedNode.text}'`, focusedNode?.parent?.text.toString(), '', '### Use the builtin `emit`, to fire this event:', `emit ${focused.text.toString()}`, `emit ${focused.text.toString()} with arguments # Specifies \`$argv\` to the event handler`, ].join('\n')), markdown_builder_1.md.separator(), markdown_builder_1.md.boldItalic('SEE ALSO:'), ' • Emit Events: https://fishshell.com/docs/current/cmds/emit.html', ' • Emit Handling: https://fishshell.com/docs/current/language.html#event', ].join(markdown_builder_1.md.newline()), definition_scope_1.DefinitionScope.create(node, 'global'))); break; default: break; } } return [functionSymbol.addChildren(...children)]; }