UNPKG

perlnavigator-server

Version:

Perl language server

156 lines 6.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.getAvailableMods = exports.getDefinition = void 0; const vscode_uri_1 = require("vscode-uri"); const fs_1 = require("fs"); const utils_1 = require("./utils"); const path_1 = require("path"); const assets_1 = require("./assets"); const refinement_1 = require("./refinement"); async function getDefinition(params, perlDoc, txtDoc, modMap) { let position = params.position; const symbol = (0, utils_1.getSymbol)(position, txtDoc); if (!symbol) return; const foundElems = (0, utils_1.lookupSymbol)(perlDoc, modMap, symbol, position.line); if (foundElems.length == 0) { return; } let locationsFound = []; for (const elem of foundElems) { const elemResolved = await resolveElemForNav(perlDoc, elem, symbol); if (!elemResolved) continue; let uri; if (perlDoc.uri !== elemResolved.uri) { // If sending to a different file, let's make sure it exists and clean up the path const file = vscode_uri_1.default.parse(elemResolved.uri).fsPath; if (!(await (0, utils_1.isFile)(file))) continue; // Make sure the file exists and hasn't been deleted. uri = vscode_uri_1.default.file((0, fs_1.realpathSync)(file)).toString(); // Resolve symlinks } else { // Sending to current file (including untitled files) uri = perlDoc.uri; } const newLoc = { uri: uri, range: { start: { line: elemResolved.line, character: 0 }, end: { line: elemResolved.line, character: 500 }, }, }; locationsFound.push(newLoc); } // const count = locationsFound return locationsFound; } exports.getDefinition = getDefinition; async function resolveElemForNav(perlDoc, elem, symbol) { let refined = await (0, refinement_1.refineElement)(elem, perlDoc); elem = refined || elem; if (!badFile(elem.uri)) { if (perlDoc.uri == elem.uri && symbol.includes("->")) { // Corinna methods don't have line numbers. Let's hunt for them. If you dont find anything better, just return the original element. const method = symbol.split("->").pop(); if (method) { // Shouldn't this always be defined? Double check const found = perlDoc.elems.get(method); if (found) { if (elem.line == 0 && elem.type == "x") { if (found[0].uri == perlDoc.uri) return found[0]; } else if (elem.line > 0 && elem.type == "t") { // Solve the off-by-one error at least for these. Eventually, you could consult a tagger for this step. for (let potentialElem of found) { if (Math.abs(potentialElem.line - elem.line) <= 1) { return potentialElem; } } } } } // Otherwise give-up } // Normal path; file is good return elem; } else { // Try looking it up by package instead of file. // Happens with XS subs and Moo subs if (elem.package) { const elemResolved = perlDoc.elems.get(elem.package); if (elemResolved) { for (let potentialElem of elemResolved) { if (potentialElem.uri && !badFile(potentialElem.uri)) { return potentialElem; } } } } // Finding the module with the stored mod didn't work. Let's try navigating to the package itself instead of Foo::Bar->method(). // Many Moose methods end up here. // Not very helpful, since the user can simply click on the module manually if they want // const base_module = symbol.match(/^([\w:]+)->\w+$/); // if(base_module){ // const elemResolved = perlDoc.elems.get(base_module); // if(elemResolved && elemResolved.file && !badFile(elem.file)){ // return elemResolved; // } // } } return; } function badFile(uri) { if (!uri) { return true; } const fsPath = vscode_uri_1.default.parse(uri).fsPath; if (!fsPath || fsPath.length <= 1) { // Single forward slashes seem to sneak in here. return true; } return /(?:Sub[\\\/]Defer\.pm|Moo[\\\/]Object\.pm|Moose[\\\/]Object\.pm|\w+\.c|Inspectorito\.pm)$/.test(fsPath); } async function getAvailableMods(workspaceFolders, settings) { let perlParams = settings.perlParams; perlParams = perlParams.concat((0, utils_1.getIncPaths)(workspaceFolders, settings)); const modHunterPath = (0, path_1.join)(await (0, assets_1.getPerlAssetsPath)(), "lib_bs22", "ModHunter.pl"); perlParams.push(modHunterPath); (0, utils_1.nLog)("Starting to look for perl modules with " + perlParams.join(" "), settings); const mods = new Map(); let output; try { // This can be slow, especially if reading modules over a network or on windows. const out = await (0, utils_1.async_execFile)(settings.perlPath, perlParams, { timeout: 90000, maxBuffer: 20 * 1024 * 1024 }); output = out.stdout; (0, utils_1.nLog)("Success running mod hunter", settings); } catch (error) { (0, utils_1.nLog)("ModHunter failed. You will lose autocomplete on importing modules. Not a huge deal", settings); (0, utils_1.nLog)(error, settings); return mods; } output.split("\n").forEach((mod) => { var items = mod.split("\t"); if (items.length != 5 || items[1] != "M" || !items[2] || !items[3]) { return; } // Load file (0, fs_1.realpath)(items[3], function (err, path) { if (err) { // Skip if error } else { if (!path) return; // Could file be empty, but no error? let uri = vscode_uri_1.default.file(path).toString(); // Resolve symlinks mods.set(items[2], uri); } }); }); return mods; } exports.getAvailableMods = getAvailableMods; //# sourceMappingURL=navigation.js.map