diff --git a/extension/README.md b/extension/README.md index 02bbaf2..1ef91d9 100644 --- a/extension/README.md +++ b/extension/README.md @@ -52,6 +52,14 @@ extension in the following ways: - Will not affect regular shell scripts, only `PKGBUILD`s +### Pacman \*.install files + +The Packaging extension adds syntax highlighting to Pacman `*.install` +files. + +It also sets Bash as the shell, removing an unnecessary Shellcheck +warning. + ### customizepkg syntax highlighting The Packaging extension provides syntax highlighting for @@ -75,7 +83,8 @@ ever. ## FAQ - Q. Why does this extension set Bash as the shell? - A. `makepkg`, the program that sources `PKGBUILD`s, runs in Bash. + A. `makepkg`, the program that sources `PKGBUILD`s, runs in Bash. + The same goes for Pacman `*.install` files. - Q. Why does this extension disable rule SC2164 for `PKGBUILD`s? A. `makepkg` first configures `shopt -o -s errexit`, which is @@ -122,7 +131,7 @@ A shout-out to these amazing people: ## License -Copyright (c) 2022 Claudia Pellegrino +Copyright (c) 2022–2024 Claudia Pellegrino Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/extension/examples/debian/foo.install b/extension/examples/debian/foo.install new file mode 100644 index 0000000..86e041d --- /dev/null +++ b/extension/examples/debian/foo.install @@ -0,0 +1,3 @@ +foo +bar +baz diff --git a/extension/examples/foo.install b/extension/examples/foo.install new file mode 100644 index 0000000..63837be --- /dev/null +++ b/extension/examples/foo.install @@ -0,0 +1,37 @@ +# The function is run right before files are extracted. +# One argument is passed: new package version. +pre_install() { + : +} + +# The function is run right after files are extracted. +# One argument is passed: new package version. +post_install() { + : +} + +# The function is run right before files are extracted. +# Two arguments are passed in the following order: +# new package version, old package version. +pre_upgrade() { + : +} + +# The function is run right after files are extracted. +# Two arguments are passed in the following order: +# new package version, old package version. +post_upgrade() { + : +} + +# The function is run right before files are removed. +# One argument is passed: old package version. +pre_remove() { + : +} + +# The function is run right after files are removed. +# One argument is passed: old package version. +post_remove() { + : +} diff --git a/extension/share/dist/package.json b/extension/share/dist/package.json index be5aeb1..76b69f5 100644 --- a/extension/share/dist/package.json +++ b/extension/share/dist/package.json @@ -30,6 +30,16 @@ "2154", "2164" ] + }, + "[pacman-install-script]": { + "shellcheck.customArgs": [ + "--external-sources", + "--shell", + "bash" + ] + }, + "files.associations": { + "**/debian/*.install": "plain" } }, "grammars": [ @@ -38,6 +48,11 @@ "scopeName": "source.shell.pkgbuild.aur", "path": "language/aur-pkgbuild.tmLanguage.json" }, + { + "language": "pacman-install-script", + "scopeName": "source.shell.install-script.pacman", + "path": "language/pacman-install-script.tmLanguage.json" + }, { "language": "customizepkg-patch", "scopeName": "source.customizepkg-patch", @@ -55,6 +70,16 @@ ], "configuration": "language/aur-pkgbuild.language-configuration.json" }, + { + "id": "pacman-install-script", + "aliases": [ + "Pacman *.install script" + ], + "filenamePatterns": [ + "**/*.install" + ], + "configuration": "language/pacman-install-script.language-configuration.json" + }, { "id": "customizepkg-patch", "aliases": [ diff --git a/extension/share/language/pacman-install-script.language-configuration.json b/extension/share/language/pacman-install-script.language-configuration.json new file mode 100644 index 0000000..227126d --- /dev/null +++ b/extension/share/language/pacman-install-script.language-configuration.json @@ -0,0 +1,86 @@ +{ + "comments": { + "lineComment": "#" + }, + "brackets": [ + [ + "{", + "}" + ], + [ + "[", + "]" + ], + [ + "(", + ")" + ] + ], + "autoClosingPairs": [ + [ + "{", + "}" + ], + [ + "[", + "]" + ], + [ + "(", + ")" + ], + { + "open": "\"", + "close": "\"", + "notIn": [ + "string" + ] + }, + { + "open": "'", + "close": "'", + "notIn": [ + "string" + ] + }, + { + "open": "`", + "close": "`", + "notIn": [ + "string" + ] + } + ], + "surroundingPairs": [ + [ + "{", + "}" + ], + [ + "[", + "]" + ], + [ + "(", + ")" + ], + [ + "\"", + "\"" + ], + [ + "'", + "'" + ], + [ + "`", + "`" + ] + ], + "folding": { + "markers": { + "start": "^\\s*#\\s*#?region\\b.*", + "end": "^\\s*#\\s*#?endregion\\b.*" + } + } +} diff --git a/extension/share/language/pacman-install-script.tmLanguage.json b/extension/share/language/pacman-install-script.tmLanguage.json new file mode 100644 index 0000000..83865e4 --- /dev/null +++ b/extension/share/language/pacman-install-script.tmLanguage.json @@ -0,0 +1,11 @@ +{ + "name": "pacman-install-script", + "scopeName": "source.shell.install-script.pacman", + "uuid": "04125485-6333-4e94-aad4-6b5983795a02", + "comment": "Pacman *.install script", + "patterns": [ + { + "include": "source.shell" + } + ] +} diff --git a/extension/src/extension.ts b/extension/src/extension.ts index fe8fea9..ab6fd5c 100644 --- a/extension/src/extension.ts +++ b/extension/src/extension.ts @@ -5,7 +5,12 @@ import { extensions, } from "vscode"; -import { statusItem } from "./language"; +import { + PACMAN_INSTALL_SCRIPT_SELECTOR, + pacmanInstallScriptStatusItem, + PKGBUILD_SELECTOR, + pkgbuildStatusItem, +} from "./language"; import log from "./log"; import { SubscriptionHelper } from "./shellcheck"; @@ -20,20 +25,26 @@ function packageJson(context: ExtensionContext): ExtensionPackageJson { export function activate(context: ExtensionContext) { commands.registerCommand("packaging.action.showLog", log.show, log); - statusItem.command = { + pacmanInstallScriptStatusItem.command = { command: "packaging.action.showLog", title: "Show extension log", }; + pkgbuildStatusItem.command = { ...pacmanInstallScriptStatusItem.command }; - const helper: SubscriptionHelper = new SubscriptionHelper(context); - let subscription: Disposable | null = helper.trySubscribe(); - extensions.onDidChange((_) => { - if (subscription) { - subscription = helper.refresh(subscription); - } else { - subscription = helper.trySubscribe(); - } - }); + const helpers: SubscriptionHelper[] = [ + new SubscriptionHelper(context, PACMAN_INSTALL_SCRIPT_SELECTOR), + new SubscriptionHelper(context, PKGBUILD_SELECTOR), + ]; + for (const helper of helpers) { + let subscription: Disposable | null = helper.trySubscribe(); + extensions.onDidChange((_) => { + if (subscription) { + subscription = helper.refresh(subscription); + } else { + subscription = helper.trySubscribe(); + } + }); + } const { version } = packageJson(context); log.info(`Extension v${version} startup successful`); diff --git a/extension/src/language.ts b/extension/src/language.ts index fa779fa..da21719 100644 --- a/extension/src/language.ts +++ b/extension/src/language.ts @@ -1,9 +1,19 @@ import { DocumentFilter, languages, LanguageStatusItem } from "vscode"; -export const LANGUAGE_SELECTOR: DocumentFilter = { language: "aur-pkgbuild" }; +export const PKGBUILD_SELECTOR: DocumentFilter = { language: "aur-pkgbuild" }; -export const statusItem: LanguageStatusItem = languages +export const pkgbuildStatusItem: LanguageStatusItem = languages .createLanguageStatusItem( "aur-pkgbuild.status.item", - LANGUAGE_SELECTOR, + PKGBUILD_SELECTOR, + ); + +export const PACMAN_INSTALL_SCRIPT_SELECTOR: DocumentFilter = { + language: "pacman-install-script", +}; + +export const pacmanInstallScriptStatusItem: LanguageStatusItem = languages + .createLanguageStatusItem( + "pacman-install-script", + PACMAN_INSTALL_SCRIPT_SELECTOR, ); diff --git a/extension/src/shellcheck.ts b/extension/src/shellcheck.ts index fca589f..b48f553 100644 --- a/extension/src/shellcheck.ts +++ b/extension/src/shellcheck.ts @@ -6,7 +6,6 @@ import { extensions, } from "vscode"; -import { LANGUAGE_SELECTOR } from "./language"; import log from "./log"; const SHELLCHECK_EXTENSION: string = "timonwong.shellcheck"; @@ -18,9 +17,13 @@ export interface ShellCheckExtensionApiVersion1 { export class SubscriptionHelper { #context: ExtensionContext; #firstTry = true; + #prefix: string; + #selector: DocumentFilter; - constructor(context: ExtensionContext) { + constructor(context: ExtensionContext, selector: DocumentFilter) { this.#context = context; + this.#prefix = selector.language ?? JSON.stringify(selector); + this.#selector = { ...selector }; } trySubscribe(): Disposable | null { @@ -28,16 +31,18 @@ export class SubscriptionHelper { if (subscription) { if (this.#firstTry) { - log.info("Connected to ShellCheck extension."); + log.info(`${this.#prefix}: Connected to ShellCheck extension.`); } else { - log.info("ShellCheck extension has appeared. Connected."); + log.info(`${this.#prefix}:` + + " ShellCheck extension has appeared. Connected."); } } else { // eslint-disable-next-line no-lonely-if if (this.#firstTry) { - log.info("ShellCheck extension not active."); + log.info(`${this.#prefix}: ShellCheck extension not active.`); } else { - log.info("Extensions have changed but still no sign of ShellCheck."); + log.info(`${this.#prefix}:` + + " Extensions have changed but still no sign of ShellCheck."); } } @@ -51,10 +56,12 @@ export class SubscriptionHelper { */ refresh(subscription: Disposable): Disposable | null { if (SubscriptionHelper.#api()) { - log.info("Extensions have changed but ShellCheck is still around."); + log.info(`${this.#prefix}:` + + " Extensions have changed but ShellCheck is still around."); return subscription; } - log.info("ShellCheck extension has gone away. Cleaning up."); + log.info(`${this.#prefix}:` + + "ShellCheck extension has gone away. Cleaning up."); subscription.dispose(); return null; } @@ -68,12 +75,12 @@ export class SubscriptionHelper { || !("apiVersion1" in shellCheckExtension.exports)) { log.error( "The ShellCheck extension is active but did not provide an API surface." - + " Is the ShellCheck extension outdated?", + + " Is the ShellCheck extension outdated?", ); return null; } - const {apiVersion1} = shellCheckExtension.exports as - {apiVersion1: ShellCheckExtensionApiVersion1}; + const { apiVersion1 } = shellCheckExtension.exports as + { apiVersion1: ShellCheckExtensionApiVersion1 }; return apiVersion1; } @@ -83,8 +90,7 @@ export class SubscriptionHelper { return null; } - const subscription: Disposable = - api.registerDocumentFilter(LANGUAGE_SELECTOR); + const subscription: Disposable = api.registerDocumentFilter(this.#selector); this.#context.subscriptions.push(subscription); return subscription; }