From 18b131a1381c00d4260d1c94da8242d1a9df2d5f Mon Sep 17 00:00:00 2001 From: Heitor Augusto Date: Sun, 25 Aug 2024 16:23:06 +0000 Subject: [PATCH] Add module for Ghostwriter --- modules/apps/default.nix | 1 + modules/apps/ghostwriter.nix | 588 +++++++++++++++++++++++++++++++++++ modules/files.nix | 2 + 3 files changed, 591 insertions(+) create mode 100644 modules/apps/ghostwriter.nix diff --git a/modules/apps/default.nix b/modules/apps/default.nix index 748a7fa4..80974fd5 100644 --- a/modules/apps/default.nix +++ b/modules/apps/default.nix @@ -2,6 +2,7 @@ { imports = [ + ./ghostwriter.nix ./konsole.nix ./kate ./okular.nix diff --git a/modules/apps/ghostwriter.nix b/modules/apps/ghostwriter.nix new file mode 100644 index 00000000..d2322c4f --- /dev/null +++ b/modules/apps/ghostwriter.nix @@ -0,0 +1,588 @@ +{ config, lib, pkgs, ... }: +let + cfg = config.programs.ghostwriter; + + qfont = import ../../lib/qfont.nix { inherit lib; }; + + getIndexFromEnum = enum: value: + if value == null + then null + else + lib.lists.findFirstIndex + (x: x == value) + (throw "getIndexFromEnum (ghostwriter): Value ${value} isn't present in the enum. This is a bug") + enum; + + getBoolFromEnum = enum: value: + if (getIndexFromEnum enum value) == 0 + then false + else true; + + styleStrategyType = lib.types.submodule { + options = with qfont.styleStrategy; { + prefer = lib.mkOption { + type = prefer; + default = "default"; + description = '' + Which type of font is preferred by the font when finding an appropriate default family. + + `default`, `bitmap`, `device`, `outline`, `forceOutline` correspond to the + `PreferDefault`, `PreferBitmap`, `PreferDevice`, `PreferOutline`, `ForceOutline` enum flags + respectively. + ''; + }; + matchingPrefer = lib.mkOption { + type = matchingPrefer; + default = "default"; + description = '' + Whether the font matching process prefers exact matches, of best quality matches. + + `default` corresponds to not setting any enum flag, and `exact` and `quality` + correspond to `PreferMatch` and `PreferQuality` enum flags respectively. + ''; + }; + antialiasing = lib.mkOption { + type = antialiasing; + default = "default"; + description = '' + Whether antialiasing is preferred for this font. + + `default` corresponds to not setting any enum flag, and `prefer` and `disable` + correspond to `PreferAntialias` and `NoAntialias` enum flags respectively. + ''; + }; + noSubpixelAntialias = lib.mkOption { + type = lib.types.bool; + default = false; + description = '' + If set to true, this font will try to avoid subpixel antialiasing. + + Corresponds to the `NoSubpixelAntialias` enum flag. + ''; + }; + noFontMerging = lib.mkOption { + type = lib.types.bool; + default = false; + description = '' + If set to true, this font will not try to find a substitute font when encountering missing glyphs. + + Corresponds to the `NoFontMerging` enum flag. + ''; + }; + preferNoShaping = lib.mkOption { + type = lib.types.bool; + default = false; + description = '' + If set to true, this font will not try to apply shaping rules that may be required for some scripts + (e.g. Indic scripts), increasing performance if these rules are not required. + + Corresponds to the `PreferNoShaping` enum flag. + ''; + }; + }; + }; + + fontType = lib.types.submodule { + options = { + family = lib.mkOption { + type = lib.types.str; + description = "The font family of this font."; + example = "Noto Sans"; + }; + pointSize = lib.mkOption { + type = lib.types.nullOr lib.types.numbers.positive; + default = null; + description = '' + The point size of this font. + + Could be a decimal, but usually an integer. Mutually exclusive with pixel size. + ''; + }; + pixelSize = lib.mkOption { + type = lib.types.nullOr lib.types.ints.u16; + default = null; + description = '' + The pixel size of this font. + + Mutually exclusive with point size. + ''; + }; + styleHint = lib.mkOption { + type = qfont.styleHint; + default = "anyStyle"; + description = '' + The style hint of this font. + + See https://doc.qt.io/qt-6/qfont.html#StyleHint-enum for more. + ''; + }; + weight = lib.mkOption { + type = lib.types.either (lib.types.ints.between 1 1000) qfont.weight; + default = "normal"; + description = '' + The weight of the font, either as a number between 1 to 1000 or as a pre-defined weight string. + + See https://doc.qt.io/qt-6/qfont.html#Weight-enum for more. + ''; + }; + style = lib.mkOption { + type = qfont.style; + default = "normal"; + description = "The style of the font."; + }; + underline = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Whether the font is underlined."; + }; + strikeOut = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Whether the font is struck out."; + }; + fixedPitch = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Whether the font has a fixed pitch."; + }; + capitalization = lib.mkOption { + type = qfont.capitalization; + default = "mixedCase"; + description = '' + The capitalization settings for this font. + + See https://doc.qt.io/qt-6/qfont.html#Capitalization-enum for more. + ''; + }; + letterSpacingType = lib.mkOption { + type = qfont.spacingType; + default = "percentage"; + description = '' + Whether to use percentage or absolute spacing for this font. + + See https://doc.qt.io/qt-6/qfont.html#SpacingType-enum for more. + ''; + }; + letterSpacing = lib.mkOption { + type = lib.types.number; + default = 0; + description = '' + The amount of letter spacing for this font. + + Could be a percentage or an absolute spacing change (positive increases spacing, negative decreases spacing), + based on the selected `letterSpacingType`. + ''; + }; + wordSpacing = lib.mkOption { + type = lib.types.number; + default = 0; + description = '' + The amount of word spacing for this font, in pixels. + + Positive values increase spacing while negative ones decrease spacing. + ''; + }; + stretch = lib.mkOption { + type = lib.types.either (lib.types.ints.between 1 4000) qfont.stretch; + default = "anyStretch"; + description = '' + The stretch factor for this font, as an integral percentage (i.e. 150 means a 150% stretch), + or as a pre-defined stretch factor string. + ''; + }; + styleStrategy = lib.mkOption { + type = styleStrategyType; + default = { }; + description = '' + The strategy for matching similar fonts to this font. + + See https://doc.qt.io/qt-6/qfont.html#StyleStrategy-enum for more. + ''; + }; + styleName = lib.mkOption { + type = lib.types.nullOr lib.types.str; + default = null; + description = '' + The style name of this font, overriding the `style` and `weight` parameters when set. + Used for special fonts that have styles beyond traditional settings. + ''; + }; + }; + }; +in +{ + options.programs.ghostwriter = { + enable = lib.mkEnableOption '' + Enable configuration management for Ghostwriter. + ''; + + package = lib.mkPackageOption pkgs [ "kdePackages" "ghostwriter" ] { + example = pkgs.libsForQt5.ghostwriter; + }; + + locale = lib.mkOption { + type = lib.types.nullOr lib.types.str; + default = null; + example = "en_US"; + description = '' + The locale to use for Ghostwriter. + ''; + }; + + font = lib.mkOption { + type = lib.types.nullOr fontType; + default = null; + example = { + family = "Noto Sans"; + pointSize = 12; + style = "normal"; + }; + description = '' + The font to use for the editor in Ghostwriter. + ''; + apply = font: if font == null then null else qfont.fontToString font; + }; + + editor = { + styling = { + blockquoteStyle = + let enumVals = [ "simple" "italic" ]; + in lib.mkOption { + type = lib.types.nullOr (lib.types.enum enumVals); + default = null; + example = "simple"; + description = "The style of blockquotes."; + apply = getBoolFromEnum enumVals; + }; + editorWidth = + let enumVals = [ "narrow" "medium" "wide" "full" ]; + in lib.mkOption { + type = lib.types.nullOr (lib.types.enum enumVals); + default = null; + example = "medium"; + description = "The width of the editor."; + apply = getIndexFromEnum enumVals; + }; + emphasisStyle = + let enumVals = [ "italic" "underline" ]; + in lib.mkOption { + type = lib.types.nullOr (lib.types.enum enumVals); + default = null; + example = "bold"; + description = "The style of emphasis."; + apply = getBoolFromEnum enumVals; + }; + focusMode = + let enumVals = [ "sentence" "currentLine" "threeLines" "paragraph" "typewriter" ]; + in lib.mkOption { + type = lib.types.nullOr (lib.types.enum enumVals); + default = null; + example = "sentence"; + description = "The focus mode to use."; + apply = focusMode: + if focusMode == null + then null + else builtins.elemAt [ 1 2 3 4 5 ]; ( + lib.lists.findFirstIndex + (x: x == focusMode) + (throw "editor.styling.focusMode: Value ${focusMode} isn't present in the enum. This is a bug") + enumVals; + ); + }; + useLargeHeadings = lib.mkOption { + type = lib.types.nullOr lib.types.bool; + default = null; + example = true; + description = "Whether to use large headings."; + }; + }; + tabulation = { + insertSpaces = lib.mkOption { + type = lib.types.nullOr lib.types.bool; + default = null; + example = true; + description = "Whether to insert spaces instead of tabs."; + }; + tabWidth = lib.mkOption { + type = lib.types.nullOr lib.types.ints.positive; + default = null; + example = 4; + description = "The width of a tab in spaces."; + }; + }; + typing = { + automaticallyMatchCharacters = { + enable = lib.mkOption { + type = lib.types.nullOr lib.types.bool; + default = null; + example = true; + description = "Whether to automatically match characters."; + }; + characters = lib.mkOption { + type = lib.types.nullOr lib.types.str; + default = null; + example = "\"'([{*_`<"; + description = "The characters to automatically match."; + }; + }; + bulletPointCycling = lib.mkOption { + type = lib.types.nullOr lib.types.bool; + default = null; + example = true; + description = "Whether to cycle through bullet points."; + }; + }; + }; + + general = { + display = { + hideMenubarInFullscreen = lib.mkOption { + type = lib.types.nullOr lib.types.bool; + default = null; + example = true; + description = "Whether to hide the menubar in fullscreen mode."; + }; + interfaceStyle = + let enumVals = [ "rounded" "square" ]; + in lib.mkOption { + type = lib.types.nullOr (lib.types.enum enumVals); + default = null; + example = "rounded"; + description = "The interface style to use for Ghostwriter."; + apply = getIndexFromEnum enumVals; + }; + showCurrentTimeInFullscreen = lib.mkOption { + type = lib.types.nullOr lib.types.bool; + default = null; + example = true; + description = "Whether to show the current time in fullscreen mode."; + }; + showUnbreakableSpace = lib.mkOption { + type = lib.types.nullOr lib.types.bool; + default = null; + example = true; + description = "Whether to show unbreakable space."; + }; + }; + fileSaving = { + autoSave = lib.mkOption { + type = lib.types.nullOr lib.types.bool; + default = null; + example = true; + description = "Whether to enable auto-save."; + }; + backupFileOnSave = lib.mkOption { + type = lib.types.nullOr lib.types.bool; + default = null; + example = true; + description = "Whether to backup the file on save."; + }; + backupLocation = lib.mkOption { + type = lib.types.nullOr lib.types.path; + default = null; + example = "/home/user/.local/share/ghostwriter/backups"; + description = '' + The location to store backups of the Ghostwriter configuration. + ''; + }; + }; + session = { + openLastFileOnStartup = lib.mkOption { + type = lib.types.nullOr lib.types.bool; + default = null; + example = true; + description = "Whether to open the last file on startup."; + }; + rememberRecentFiles = lib.mkOption { + type = lib.types.nullOr lib.types.bool; + default = null; + example = true; + description = "Whether to remember recent files."; + }; + }; + }; + + preview = { + commandLineArguments = lib.mkOption { + type = lib.types.nullOr lib.types.str; + default = null; + description = "The command line arguments to pass to the previewer."; + }; + codeFont = lib.mkOption { + type = lib.types.nullOr fontType; + default = null; + example = { + family = "Fira Code"; + pointSize = 12; + style = "normal"; + }; + description = '' + The font to use for code previews in Ghostwriter. + ''; + apply = font: if font == null then null else qfont.fontToString font; + }; + markdownVariant = lib.mkOption { + type = lib.types.nullOr lib.types.str; + default = null; + example = "cmark-gfm"; + description = '' + The markdown variant in Ghostwriter. + ''; + }; + textFont = lib.mkOption { + type = lib.types.nullOr fontType; + default = null; + example = { + family = "Noto Serif"; + pointSize = 12; + style = "normal"; + }; + description = '' + The font to use for text previews in Ghostwriter. + ''; + apply = font: if font == null then null else qfont.fontToString font; + }; + }; + + spelling = { + autoDetectLanguage = lib.mkOption { + type = lib.types.nullOr lib.types.bool; + default = null; + example = true; + description = "Whether to auto-detect the language."; + }; + checkerEnabledByDefault = lib.mkOption { + type = lib.types.nullOr lib.types.bool; + default = null; + example = true; + description = "Whether the checker is enabled by default."; + }; + ignoreUppercase = lib.mkOption { + type = lib.types.nullOr lib.types.bool; + default = null; + example = true; + description = "Whether to ignore uppercase words."; + }; + ignoredWords = lib.mkOption { + type = lib.types.nullOr (lib.types.listOf lib.types.str); + default = null; + example = [ "Amarok" "KHTML" "NixOS" ]; + description = "Words to ignore in the spell checker."; + apply = ignoredWords: if ignoredWords == null then null else builtins.concatStringsSep ", " ignoredWords; + }; + liveSpellCheck = lib.mkOption { + type = lib.types.nullOr lib.types.bool; + default = null; + example = true; + description = "Whether to enable live spell checking."; + }; + skipRunTogether = lib.mkOption { + type = lib.types.nullOr lib.types.bool; + default = null; + example = true; + description = "Whether to skip run-together words."; + }; + }; + + theme = { + name = lib.mkOption { + type = lib.types.nullOr lib.types.str; + default = null; + example = "Classic"; + description = "The theme to use for Ghostwriter."; + }; + }; + + window.sidebarOpen = lib.mkOption { + type = lib.types.nullOr lib.types.bool; + default = null; + example = true; + description = "Whether the sidebar is open by default."; + }; + }; + + config = lib.mkIf cfg.enable { + home.packages = [ cfg.package ]; + + programs.plasma.configFile."kde.org/ghostwriter.conf" = + let + applyIfSet = opt: lib.mkIf (opt != null) opt; + in + { + Application = { + locale = applyIfSet cfg.locale; + }; + + Backup = { + location = applyIfSet cfg.general.fileSaving.backupLocation; + }; + + Preview = { + codeFont = applyIfSet cfg.preview.codeFont; + lastUsedExporter = applyIfSet cfg.preview.markdownVariant; + lastUsedExporterParams = applyIfSet cfg.preview.commandLineArguments; + textFont = applyIfSet cfg.preview.textFont; + }; + + Save = { + autoSave = applyIfSet cfg.general.fileSaving.autoSave; + backupFile = applyIfSet cfg.general.fileSaving.backupFileOnSave; + }; + + Session = { + restoreSession = applyIfSet cfg.general.session.openLastFileOnStartup; + rememberFileHistory = applyIfSet cfg.general.session.rememberRecentFiles; + }; + + Spelling = { + liveSpellCheck = applyIfSet cfg.spelling.liveSpellCheck; + }; + + style = { + showUnbreakableSpace = applyIfSet cfg.display.showUnbreakableSpace; + }; + + Style = { + blockquoteStyle = applyIfSet cfg.editor.styling.blockquoteStyle; + displayTimeInFullscreen = applyIfSet cfg.style.displayTimeInFullscreen; + editorFont = applyIfSet cfg.font; + editorWidth = applyIfSet cfg.editor.styling.editorWidth; + focusMode = applyIfSet cfg.editor.styling.focusMode; + hideMenubarInFullscreen = applyIfSet cfg.style.hideMenubarInFullscreen; + interfaceStyle = applyIfSet cfg.display.interfaceStyle; + largeHeadings = applyIfSet cfg.editor.styling.useLargeHeadings; + underlineInsteadOfItalics = applyIfSet cfg.editor.styling.emphasisStyle; + theme = applyIfSet cfg.theme.name; + }; + + Tabs = { + insertSpacesForTabs = applyIfSet cfg.editor.tabulation.insertSpaces; + tabWidth = applyIfSet cfg.editor.tabulation.tabWidth; + }; + + Typing = { + autoMatchEnabled = applyIfSet cfg.editor.typing.automaticallyMatchCharacters.enable; + autoMatchFilter = applyIfSet cfg.editor.typing.automaticallyMatchCharacters.characters; + bulletPointCyclingEnabled = applyIfSet cfg.editor.typing.bulletPointCycling; + }; + + Window = { + sidebarOpen = applyIfSet cfg.window.sidebarOpen; + }; + }; + + programs.plasma.configFile."KDE/Sonnet.conf" = + let + applyIfSet = opt: lib.mkIf (opt != null) opt; + in + { + General = { + autodetectLanguage = applyIfSet cfg.spelling.autoDetectLanguage; + checkerEnabledByDefault = applyIfSet cfg.spelling.checkerEnabledByDefault; + checkUppercase = applyIfSet !cfg.spelling.ignoreUppercase; + defaultLanguage = applyIfSet cfg.locale; + "ignore_${cfg.locale}" = applyIfSet cfg.spelling.ignoredWords; + }; + }; + }; +} \ No newline at end of file diff --git a/modules/files.nix b/modules/files.nix index 49af6422..0d509358 100644 --- a/modules/files.nix +++ b/modules/files.nix @@ -34,6 +34,8 @@ let "kactivitymanagerdrc" "katerc" "kcminputrc" + "KDE/Sonnet.conf" + "kde.org/ghostwriter.conf" "kded5rc" "kded6rc" "kdeglobals"