Skip to content

Commit

Permalink
feat: added support for NixOS config files (#229)
Browse files Browse the repository at this point in the history
* add support for .nix (NixOS) config files

* removed nixos provider import of javascript provider function

* Fixed leftover mistake from previous commit
  • Loading branch information
KhanKudo authored May 31, 2024
1 parent f668e86 commit 6aa458c
Show file tree
Hide file tree
Showing 10 changed files with 137 additions and 4 deletions.
2 changes: 2 additions & 0 deletions src/providers/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { PathIntellisenseProvider } from "./provider.interface";
import { DefaultProvider } from "./default.provider";
import { JavaScriptProvider } from "./javascript/javascript.provider";
import { NixProvider } from './nixos/nixos.provider';

export const providers: PathIntellisenseProvider[] = [
JavaScriptProvider,
NixProvider,
DefaultProvider,
];
4 changes: 2 additions & 2 deletions src/providers/javascript/javascript.provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import * as vscode from "vscode";
import { PathIntellisenseProvider } from "../provider.interface";
import { getConfiguration } from "../../configuration/configuration.service";
import { Config, Mapping } from "../../configuration/configuration.interface";
import { createContext, Context } from "./createContext";
import { createContext, Context } from "../../utils/createContext";

import { createPathCompletionItem } from "./createCompletionItem";
import { createPathCompletionItem } from "../../utils/createCompletionItem";
import {
getPathOfFolderToLookupFiles,
getChildrenOfPath,
Expand Down
106 changes: 106 additions & 0 deletions src/providers/nixos/nixos.provider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import * as vscode from "vscode";
import { PathIntellisenseProvider } from "../provider.interface";
import { getConfiguration } from "../../configuration/configuration.service";
import { Config, Mapping } from "../../configuration/configuration.interface";
import { createContext, Context } from "../../utils/createContext";
import { getChildrenOfPath, getPathOfFolderToLookupFiles } from '../../utils/file-utills';
import { createPathCompletionItem } from '../../utils/createCompletionItem';

export const NixProvider: PathIntellisenseProvider = {
selector: {
pattern: '**/*.nix',
scheme: 'file'
},
provider: {
provideCompletionItems,
},
triggerCharacters: ["/"],
};

async function provideCompletionItems(
document: vscode.TextDocument,
position: vscode.Position
): Promise<vscode.CompletionItem[]> {
const context = createContext(document, position);
const config = await getConfiguration(document.uri);

const typedString = getTypedString(context, config);
return typedString === null
? Promise.resolve([])
: provide(context, config, typedString);
}

/**
* Returns the currently typed string, prior to the cursor position.
* Should have the same effect as context.fromString, expect that it doesn't
* require string quotations to be present, making it compatible with nix files.
* This is important because in nix, string quoted paths are explicitly forced as absolute,
* a relative path may not use any quotations, making context.fromString return null.
* This function will too return null if it decides a path completion is not appropriate
* at the current cursor position.
* @param context
* @param config
*/
function getTypedString(context: Context, config: Config): null | string {
const { fromString: contextFromString } = context;

let noQuoteString: undefined | string = undefined;

if (!contextFromString) {
const cursorPos = context.importRange.start.character;
const lineUpToCursor = context.textFullLine.slice(0, cursorPos);
noQuoteString = lineUpToCursor.match(/\.{0,2}\/[^\"\'\,\s]*$/)?.[0];
}

const fromString = noQuoteString ?? contextFromString;

if (fromString) {
const startsWithDot = fromString[0] === ".";
const startsWithSlash = fromString[0] === "/";
const startsWithMapping = config.mappings.some(({ key }) =>
fromString.startsWith(key)
);

return (
startsWithDot ||
startsWithMapping ||
(startsWithSlash && config.showOnAbsoluteSlash)
) ? fromString : null;
}

return null;
}

/**
* Provide Completion Items
*/
async function provide(
context: Context,
config: Config,
directPathString: string
): Promise<vscode.CompletionItem[]> {
const workspace = vscode.workspace.getWorkspaceFolder(context.document.uri);

const rootPath =
config.absolutePathTo ||
(config.absolutePathToWorkspace ? workspace?.uri.fsPath : undefined);

const path = getPathOfFolderToLookupFiles(
context.document.uri.fsPath,
directPathString,
rootPath,
config.mappings
);

const childrenOfPath = await getChildrenOfPath(
path,
config.showHiddenFiles,
config.filesExclude
);

return [
...childrenOfPath.map((child) =>
createPathCompletionItem(child, config, context)
),
];
}
3 changes: 3 additions & 0 deletions src/test/demo-workspace/demo.code-workspace
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@
},
{
"path": "project-withBaseUrlRoot2"
},
{
"path": "project-nixos-config"
}
],
"settings": {
Expand Down
4 changes: 4 additions & 0 deletions src/test/demo-workspace/project-nixos-config/apps/vscode.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
# test of absolute import paths with strings home-assistant import from sibling folder
testPath = [ "/services/" ]
}
12 changes: 12 additions & 0 deletions src/test/demo-workspace/project-nixos-config/configuration.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{ config, pkgs, ... }:

{
imports =
[
# test if path completion works without string quotes
./apps/
]
++ [./services/]; # check if path completion still work even with characters prefixed

system.stateVersion = "23.11";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{ config, pkgs, ... }:

{
# path completion for above "test.nix"
test.path = [ ../ ]
}
Empty file.
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as vscode from "vscode";
import { Context } from "./createContext";
import { Config } from "../../configuration/configuration.interface";
import { FileInfo } from "../../utils/file-utills";
import { Config } from "../configuration/configuration.interface";
import { FileInfo } from "./file-utills";

export function createPathCompletionItem(
fileInfo: FileInfo,
Expand Down
File renamed without changes.

0 comments on commit 6aa458c

Please sign in to comment.