fish-lsp
Version:
LSP implementation for fish/fish-shell
178 lines (177 loc) • 6.42 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Workspace = void 0;
exports.initializeDefaultFishWorkspaces = initializeDefaultFishWorkspaces;
exports.getRelevantDocs = getRelevantDocs;
const fastGlob = __importStar(require("fast-glob"));
const fs_1 = require("fs");
const translation_1 = require("./translation");
const config_1 = require("../config");
const logger_1 = require("../logger");
async function getFileUriSet(path) {
const stream = fastGlob.stream('**/*.fish', { cwd: path, absolute: true });
const result = new Set();
for await (const entry of stream) {
const absPath = entry.toString();
const uri = (0, translation_1.pathToUri)(absPath);
result.add(uri);
}
return result;
}
async function initializeDefaultFishWorkspaces() {
const configWorkspaces = config_1.config.fish_lsp_all_indexed_paths;
// Create an array of promises by mapping over workspacePaths
const workspacePromises = configWorkspaces.map(path => Workspace.create(path));
// Wait for all promises to resolve
const defaultSpaces = await Promise.all(workspacePromises);
return defaultSpaces;
}
async function getRelevantDocs(workspaces) {
const docs = [];
for await (const ws of workspaces) {
const workspaceDocs = await ws.asyncFilter((doc) => doc.shouldAnalyzeInBackground());
docs.push(...workspaceDocs);
}
return docs;
}
class Workspace {
path;
uris;
symbols = new Map();
static async create(path) {
const foundUris = await getFileUriSet(path);
return new Workspace(path, foundUris);
}
constructor(path, fileUris) {
this.path = path;
this.uris = fileUris;
}
contains(...checkUris) {
for (const uri of checkUris) {
const uriAsPath = (0, translation_1.uriToPath)(uri);
if (!uriAsPath.startsWith(this.path)) {
return false;
}
//if (!this.uris.has(uri)) return false
}
return true;
}
add(...newUris) {
for (const newUri of newUris) {
this.uris.add(newUri);
}
}
findMatchingFishIdentifiers(fishIdentifier) {
const matches = [];
const toMatch = `/${fishIdentifier}.fish`;
for (const uri of this.uris) {
if (uri.endsWith(toMatch)) {
matches.push(uri);
}
}
return matches;
}
/**
* An immutable workspace would be '/usr/share/fish', since we don't want to
* modify the system files.
*
* A mutable workspace would be '~/.config/fish'
*/
isMutable() {
return config_1.config.fish_lsp_modifiable_paths.includes(this.path);
}
isLoadable() {
return config_1.config.fish_lsp_all_indexed_paths.includes(this.path);
}
async updateFiles() {
const newUris = await getFileUriSet(this.path);
const diff = new Set([...this.uris].filter(x => !this.uris.has(x)));
if (diff.size === 0) {
return false;
}
newUris.forEach(uri => this.uris.add(uri));
return true;
}
hasCompletionUri(fishIdentifier) {
const matchingUris = this.findMatchingFishIdentifiers(fishIdentifier);
return matchingUris.some(uri => uri.endsWith(`/completions/${fishIdentifier}.fish`));
}
hasFunctionUri(fishIdentifier) {
const matchingUris = this.findMatchingFishIdentifiers(fishIdentifier);
return matchingUris.some(uri => uri.endsWith(`/functions/${fishIdentifier}.fish`));
}
hasCompletionAndFunction(fishIdentifier) {
return this.hasFunctionUri(fishIdentifier) && this.hasCompletionUri(fishIdentifier);
}
async asyncUrisToLspDocuments() {
const readPromises = Array.from(this.uris).map(async (uri) => {
try {
const path = (0, translation_1.uriToPath)(uri);
const content = await fs_1.promises.readFile(path, 'utf8');
return (0, translation_1.toLspDocument)(path, content);
}
catch (err) {
logger_1.logger.log(`Error reading file ${uri}: ${err}`);
return null;
}
});
const docs = await Promise.all(readPromises);
return docs.filter((doc) => doc !== null);
}
async asyncForEach(callback) {
const docs = await this.asyncUrisToLspDocuments();
docs.forEach(callback);
}
async asyncFilter(callbackfn) {
const docs = await this.asyncUrisToLspDocuments();
return docs.filter(callbackfn);
}
urisToLspDocuments() {
const docs = [];
for (const uri of this.uris) {
const path = (0, translation_1.uriToPath)(uri);
const content = (0, fs_1.readFileSync)(path);
const doc = (0, translation_1.toLspDocument)(path, content.toString());
docs.push(doc);
}
return docs;
}
forEach(callback) {
for (const doc of this.urisToLspDocuments()) {
callback(doc);
}
}
filter(callbackfn) {
const result = [];
for (const doc of this.urisToLspDocuments()) {
if (callbackfn(doc)) {
result.push(doc);
}
}
return result;
}
}
exports.Workspace = Workspace;