Skip to content

Commit

Permalink
Add code lens for editing files from settings
Browse files Browse the repository at this point in the history
Add ability to open editor for file added to `dotfiles.files` settings using a code lens, to make it faster to update the files in settings.json. Changes made in the editor automatically update the file's content in settings.json if `dotfiles.autoUpdate` is enabled.
  • Loading branch information
grgar committed Mar 29, 2024
1 parent 930c19c commit 26d7c49
Show file tree
Hide file tree
Showing 8 changed files with 115 additions and 17 deletions.
10 changes: 9 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
# Changelog
### v1.1.0

- Add code lens for editing files from settings

Add ability to open editor for file added to `dotfiles.files` settings using a code lens, to make it faster to update the files in settings.json. Changes made in the editor automatically update the file's content in settings.json if `dotfiles.autoUpdate` is enabled.


- Simplify Makefile

### v1.0.1

- Refactor Configuration to a separate class
Expand Down Expand Up @@ -58,4 +67,3 @@


- Initial commit

4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ If `dotfiles.autoUpdate` is enabled, automatically apply config from settings to

writes file `$XDG_CONFIG_HOME/path/to/file.txt` with the content of the key.

A code lens is added to keys in settings.json under `dotfiles.files` to open the file in an editor. Saving the file in the editor will apply changes back to settings.json if `dotfiles.autoUpdate` is enabled.

<img src="images/code-lens.png" width="360">

## Extension Settings

||Description|Default|
Expand Down
Binary file added images/code-lens.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 9 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 11 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,19 @@
},
"description": "Apply dotfiles from settings",
"icon": "images/icon-small.png",
"version": "1.0.1",
"version": "1.1.0",
"license": "MIT",
"preview": true,
"engines": {
"vscode": "^1.74.0"
},
"categories": [
"Other"
],
"author": {
"name": "grg",
"url": "https://grg.app",
"email": "[email protected]"
},
"homepage": "https://github.com/grgar/vscode-dotfiles",
"qna": "https://github.com/grgar/vscode-dotfiles/discussions",
"bugs": {
Expand Down Expand Up @@ -68,14 +72,15 @@
"test": "vscode-test"
},
"devDependencies": {
"@types/vscode": "^1.74.0",
"@types/mocha": "^10.0.6",
"@types/node": "18.x",
"@types/vscode": "^1.74.0",
"@typescript-eslint/eslint-plugin": "^7.0.2",
"@typescript-eslint/parser": "^7.0.2",
"eslint": "^8.56.0",
"typescript": "^5.3.3",
"@vscode/test-cli": "^0.0.6",
"@vscode/test-electron": "^2.3.9"
"@vscode/test-electron": "^2.3.9",
"eslint": "^8.56.0",
"jsonc-parser": "^3.2.1",
"typescript": "^5.3.3"
}
}
16 changes: 12 additions & 4 deletions src/Configuration.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
import path from 'path';
import * as vscode from "vscode";

export const namespace = "dotfiles";

export enum Section {
directory = "directory",
files = "files",
autoUpdate = "autoUpdate",
}

export default class Configuration {
readonly namespace: string;
readonly logger?: (msg: string) => void;
Expand All @@ -11,27 +19,27 @@ export default class Configuration {
}

getDirectoryPath() {
let directory = vscode.workspace.getConfiguration(this.namespace).get<string>("directory") || process.env["XDG_CONFIG_HOME"] || path.join(process.env["HOME"]!, ".config");
let directory = vscode.workspace.getConfiguration(this.namespace).get<string>(Section.directory) || process.env["XDG_CONFIG_HOME"] || path.join(process.env["HOME"]!, ".config");
if (directory.endsWith("/")) {
return directory.slice(directory.length - 1);
}
return directory;
}

getFiles() {
return vscode.workspace.getConfiguration(this.namespace).get<{ [key: string]: string; }>("files", {});
return vscode.workspace.getConfiguration(this.namespace).get<{ [key: string]: string; }>(Section.files, {});
}

async setFiles(files: { [key: string]: string; }) {
try {
await vscode.workspace.getConfiguration(this.namespace).update("files", files, vscode.ConfigurationTarget.Global);
await vscode.workspace.getConfiguration(this.namespace).update(Section.files, files, vscode.ConfigurationTarget.Global);
} catch (err) {
this.logger?.(`${new Date().toLocaleString()}: failed to update files: ${err}`);
vscode.window.showErrorMessage("Unable to update dotfiles.files: " + err);
}
}

shouldAutoUpdate() {
return vscode.workspace.getConfiguration(this.namespace).get<boolean>("autoUpdate", false);
return vscode.workspace.getConfiguration(this.namespace).get<boolean>(Section.autoUpdate, false);
}
}
59 changes: 59 additions & 0 deletions src/SettingsLensProvider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { JSONVisitor, visit } from "jsonc-parser";
import path from "path";
import * as vscode from "vscode";

export class SettingsLensProvider implements vscode.CodeLensProvider {
private key: string;
private basePath: string;

constructor(key: string, basePath: string) {
this.key = key;
this.basePath = basePath;
}

provideCodeLenses(document: vscode.TextDocument): vscode.ProviderResult<vscode.CodeLens[]> {
return parseJSONForFileLocations(this.key, document).map(
({ name, range }) =>
new vscode.CodeLens(
range,
{
title: "open file",
command: "vscode.open",
arguments: [path.join(this.basePath, name)],
},
),
);
}
}

export interface FileLocation {
name: string;
range: vscode.Range;
}

const parseJSONForFileLocations = (filesProperty: String, document: vscode.TextDocument, buffer = document.getText()): FileLocation[] => {
let level = 0;
let inFiles = false;
const files: FileLocation[] = [];
const visitor: JSONVisitor = {
onObjectBegin() {
level++;
},
onObjectEnd() {
inFiles = false;
level--;
},
onObjectProperty(property: string, offset: number, length: number) {
if (level === 1 && property === filesProperty) {
inFiles = true;
} else if (inFiles) {
files.push({
name: property,
range: new vscode.Range(document.positionAt(offset), document.positionAt(offset + length))
});
}
},
};
visit(buffer, visitor);
return files;
};
15 changes: 11 additions & 4 deletions src/extension.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import * as fs from "fs/promises";
import path from 'path';
import * as vscode from 'vscode';
import Configuration from "./Configuration";
import Configuration, { namespace as configNamespace, Section } from "./Configuration";
import { SettingsLensProvider } from "./SettingsLensProvider";

export const configNamespace = "dotfiles";
const outputChannel = vscode.window.createOutputChannel(configNamespace);

async function apply() {
Expand Down Expand Up @@ -45,11 +45,18 @@ function didSave(doc: vscode.TextDocument) {
}

export function activate(context: vscode.ExtensionContext) {
const configuration = new Configuration(configNamespace, outputChannel.appendLine);
context.subscriptions.push(
vscode.commands.registerCommand("dotfiles.apply", apply),
vscode.workspace.onDidSaveTextDocument(didSave)
vscode.workspace.onDidSaveTextDocument(didSave),
vscode.languages.registerCodeLensProvider(
{
language: 'jsonc',
pattern: '**/settings.json',
},
new SettingsLensProvider(`${configNamespace}.${Section.files}`, configuration.getDirectoryPath()),
)
);
const configuration = new Configuration(configNamespace, outputChannel.appendLine);
if (configuration.shouldAutoUpdate()) {
apply();
}
Expand Down

0 comments on commit 26d7c49

Please sign in to comment.