Skip to content

Commit

Permalink
fix: improve filesystem completions
Browse files Browse the repository at this point in the history
  • Loading branch information
DylanPiercey committed Jul 16, 2022
1 parent 2312c36 commit 7930415
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 52 deletions.
6 changes: 6 additions & 0 deletions .changeset/eighty-books-camp.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"marko-vscode": patch
"@marko/language-server": patch
---

Improve filesystem completions.
42 changes: 22 additions & 20 deletions server/src/service/marko/complete/AttrValue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,37 +30,39 @@ export async function AttrValue({
end,
});

let segmentStart = rawValue.lastIndexOf("/", relativeOffset);
if (segmentStart === -1) segmentStart = relativeOffset;
const segmentStart = rawValue.lastIndexOf("/", relativeOffset);
if (segmentStart === -1) return; // only resolve after a slash.

const resolveRequest = rawValue.slice(0, segmentStart) || ".";
const dir = resolveUrl(resolveRequest, document.uri);
const req = rawValue.slice(0, segmentStart);
const uri = resolveUrl(req, document.uri);

if (dir?.[0] === "/") {
if (uri) {
const result: CompletionItem[] = [];
const curDir =
resolveRequest === "." ? dir : resolveUrl(".", document.uri);
const curFile = curDir === dir ? path.basename(document.uri) : undefined;
const curFile = req === "." ? path.basename(document.uri) : undefined;
const replaceRange = Range.create(
document.positionAt(start + segmentStart + 1),
document.positionAt(start + rawValue.length)
);

for (const [entry, type] of await fileSystem.readDirectory(dir)) {
for (const [entry, type] of await fileSystem.readDirectory(uri)) {
if (entry[0] !== "." && entry !== curFile) {
const isDir = type === FileType.Directory;
const label = isDir ? `${entry}/` : entry;
result.push({
label,
kind: isDir ? CompletionItemKind.Folder : CompletionItemKind.File,
textEdit: TextEdit.replace(replaceRange, label),
command: isDir
result.push(
type === FileType.Directory
? {
title: "Suggest",
command: "editor.action.triggerSuggest",
label: `${entry}/`,
kind: CompletionItemKind.Folder,
textEdit: TextEdit.replace(replaceRange, `${entry}/`),
command: {
title: "Suggest",
command: "editor.action.triggerSuggest",
},
}
: undefined,
});
: {
label: entry,
kind: CompletionItemKind.File,
textEdit: TextEdit.replace(replaceRange, entry),
}
);
}
}

Expand Down
10 changes: 6 additions & 4 deletions server/src/service/stylesheet/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,17 +166,19 @@ const StyleSheetService: Partial<Plugin> = {
return result.length ? result : undefined;
}
},
findDocumentLinks(doc) {
async findDocumentLinks(doc) {
const infoByExt = getStyleSheetInfo(doc);
const result: DocumentLink[] = [];

for (const ext in infoByExt) {
const info = infoByExt[ext];
const { service, virtualDoc } = info;

for (const link of service.findDocumentLinks(virtualDoc, info.parsed, {
resolveReference,
})) {
for (const link of await service.findDocumentLinks2(
virtualDoc,
info.parsed,
{ resolveReference }
)) {
const range = getSourceRange(doc, info, link.range);
if (range) {
result.push({
Expand Down
46 changes: 26 additions & 20 deletions server/src/utils/file-system.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,27 @@
import path from "path";
import fs from "fs/promises";
import { type FileStat, FileType } from "vscode-css-languageservice";
import { fileURLToPath } from "url";

export { FileStat, FileType };
export default {
stat,
readDirectory,
};
async function stat(fileName: string): Promise<FileStat> {
const stat = await fs.stat(fileName).catch(() => null);
async function stat(uri: string): Promise<FileStat> {
let type = FileType.Unknown;
let ctime = 0;
let mtime = 0;
let size = 0;
let ctime = -1;
let mtime = -1;
let size = -1;

if (stat) {
try {
const stat = await fs.stat(fileURLToPath(uri));
if (stat.isDirectory()) type = FileType.Directory;
else if (stat.isFile()) type = FileType.File;
ctime = stat.ctimeMs;
mtime = stat.mtimeMs;
size = stat.size;
} catch {
// ignore
}

return {
Expand All @@ -30,18 +32,22 @@ async function stat(fileName: string): Promise<FileStat> {
};
}

async function readDirectory(dir: string): Promise<[string, FileType][]> {
return (
await Promise.all(
(
await fs.readdir(dir).catch(() => [])
).map(
async (entry) =>
[entry, (await stat(path.join(dir, entry))).type] as [
string,
FileType
]
async function readDirectory(uri: string): Promise<[string, FileType][]> {
try {
const entries = await fs.readdir(fileURLToPath(uri));
const base = uri.at(-1) === "/" ? uri : `${uri}/`;
return (
await Promise.all(
entries.map(
async (entry) =>
[entry, (await stat(new URL(entry, base).toString())).type] as [
string,
FileType
]
)
)
)
).filter(([, type]) => type !== FileType.Unknown);
).filter(([, type]) => type !== FileType.Unknown);
} catch {
return [];
}
}
10 changes: 2 additions & 8 deletions server/src/utils/resolve-url.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,7 @@
export default function resolveUrl(to: string, base: string) {
try {
const baseUrl = new URL(base, "file://");
const resolved = new URL(to, baseUrl);
const { origin, protocol } = baseUrl;
if (resolved.origin === origin && resolved.protocol === protocol) {
// result is relative to the base URL.
return resolved.pathname + resolved.search + resolved.hash;
}
return resolved.toString();
const url = new URL(to, base);
if (url.protocol === "file:") return url.toString();
} catch {
return undefined;
}
Expand Down

0 comments on commit 7930415

Please sign in to comment.