neovim: add vale & ltex-lsp
This commit is contained in:
parent
aa3af5f0e5
commit
5604745c78
16 changed files with 1442 additions and 18 deletions
|
|
@ -1,5 +1,6 @@
|
||||||
{
|
{
|
||||||
imports = [
|
imports = [
|
||||||
./vesktop
|
./vesktop
|
||||||
|
./equicord
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
imports = [./options.nix];
|
||||||
|
programs.equicord.enable = true;
|
||||||
|
}
|
||||||
716
modules/home/workstation/communication/equicord/options.nix
Normal file
716
modules/home/workstation/communication/equicord/options.nix
Normal file
|
|
@ -0,0 +1,716 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
config,
|
||||||
|
...
|
||||||
|
}: let
|
||||||
|
inherit (lib) mkIf mkOption mkEnableOption mkPackageOption;
|
||||||
|
inherit (lib.types) listOf str int enum numbers oneOf nullOr attrsOf submodule bool strMatching;
|
||||||
|
mkBoolOption = default: description:
|
||||||
|
mkOption {
|
||||||
|
type = bool;
|
||||||
|
inherit default description;
|
||||||
|
};
|
||||||
|
|
||||||
|
mkLabelOption = default:
|
||||||
|
mkOption {
|
||||||
|
type = str;
|
||||||
|
inherit default;
|
||||||
|
description = "${default} label";
|
||||||
|
};
|
||||||
|
|
||||||
|
mkEquibopSelect = attr: v: attr.${v};
|
||||||
|
listToString = sep: list: builtins.concatStringsSep sep list;
|
||||||
|
|
||||||
|
rgbValue = ''([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])'';
|
||||||
|
rgbDecimal = strMatching ''${rgbValue}, *${rgbValue}, *${rgbValue}'';
|
||||||
|
hexColor = strMatching "#[[:xdigit:]]{6}";
|
||||||
|
|
||||||
|
mkHexColorOption = name:
|
||||||
|
mkOption {
|
||||||
|
type = oneOf [hexColor (enum [""])];
|
||||||
|
default = "";
|
||||||
|
description = "${name} color in hex format";
|
||||||
|
example = "#ea6962";
|
||||||
|
};
|
||||||
|
|
||||||
|
cfg = config.programs.equicord;
|
||||||
|
in {
|
||||||
|
options.programs.equicord = {
|
||||||
|
enable = mkEnableOption "Enable Equicord, for of Vencord";
|
||||||
|
package = mkPackageOption pkgs "equibop" {
|
||||||
|
default = "equibop";
|
||||||
|
example = pkgs.equicord;
|
||||||
|
};
|
||||||
|
settings = {
|
||||||
|
autoUpdate = mkEnableOption "Enable auto updating for Equicord" // {default = true;};
|
||||||
|
autoUpdateNotification = mkEnableOption "Notify when Equicord automatically updates";
|
||||||
|
useQuickCss = mkEnableOption "Enable custom CSS";
|
||||||
|
themeLinks = mkOption {
|
||||||
|
type = listOf str;
|
||||||
|
default = [];
|
||||||
|
description = "List of Discord CSS themes to install via link";
|
||||||
|
example = ["https://refact0r.github.io/midnight-discord/midnight.css"];
|
||||||
|
};
|
||||||
|
enabledThemes = mkOption {
|
||||||
|
type = listOf str;
|
||||||
|
default = [];
|
||||||
|
description = "List of themes to enable from XDG_CONFIG_HOME/equibop/themes";
|
||||||
|
};
|
||||||
|
enableReactDevtools = mkEnableOption "Enable react dev tools extension";
|
||||||
|
frameless = mkEnableOption "Enable frameless mode";
|
||||||
|
transparent = mkEnableOption "Enable transparent mode. Requires a theme that supports transparency";
|
||||||
|
disableMinSize = mkEnableOption "Disable minimum window size";
|
||||||
|
notifications = {
|
||||||
|
timeout = mkOption {
|
||||||
|
type = int;
|
||||||
|
default = 5000;
|
||||||
|
description = "Notification timeout in ms, set to 0 to never automatically time out";
|
||||||
|
example = 0;
|
||||||
|
};
|
||||||
|
position = mkOption {
|
||||||
|
type = enum ["bottom-right" "top-right"];
|
||||||
|
default = "bottom-right";
|
||||||
|
description = "Position of notifications";
|
||||||
|
example = "top-right";
|
||||||
|
};
|
||||||
|
useNative = mkOption {
|
||||||
|
type = enum ["always" "never" "not-focused"];
|
||||||
|
default = "not-focused";
|
||||||
|
description = "When should notifications be used";
|
||||||
|
example = "always";
|
||||||
|
};
|
||||||
|
logLimit = mkOption {
|
||||||
|
type = int;
|
||||||
|
default = 50;
|
||||||
|
description = ''
|
||||||
|
The amount of notifications to save in the log until old ones are removed.
|
||||||
|
Set to 0 to disable log. Set to 0 to to disable notification log and 200 to
|
||||||
|
never automatically remove old notifcations
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
plugins = {
|
||||||
|
# API plugins
|
||||||
|
ChatInputButtonsAPI.enabled = mkBoolOption true "Chat Input API";
|
||||||
|
CommandsAPI.enabled = mkBoolOption true "";
|
||||||
|
DynamicImageModalAPI.enabled = mkBoolOption false "";
|
||||||
|
MemberListDecoratorsAPI.enabled = mkBoolOption false "";
|
||||||
|
MessageAccessoriesAPI.enabled = mkBoolOption true "";
|
||||||
|
MessageDecorationsAPI.enabled = mkBoolOption false "";
|
||||||
|
MessageEventsAPI.enabled = mkBoolOption false "";
|
||||||
|
MessageUpdaterAPI.enabled = mkBoolOption false "";
|
||||||
|
ServerListAPI.enabled = mkBoolOption false "";
|
||||||
|
UserSettingsAPI.enabled = mkBoolOption true "";
|
||||||
|
|
||||||
|
AccountPanelServerProfile = {
|
||||||
|
enabled = mkEnableOption ''
|
||||||
|
Right click your account panel in the bottom left to
|
||||||
|
view your profile in the current server.
|
||||||
|
'';
|
||||||
|
prioritizeServerProfile = mkEnableOption ''
|
||||||
|
Prioritize Server Profile when left clicking your account panel.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
AllCallTimers = {
|
||||||
|
enabled = mkEnableOption ''
|
||||||
|
Add call timer to all users in a server voice channel.
|
||||||
|
'';
|
||||||
|
showWithoutHover = mkEnableOption ''
|
||||||
|
Always show the timer without needing to hover.
|
||||||
|
'';
|
||||||
|
showRoleColor = mkEnableOption ''
|
||||||
|
Show the users role color.
|
||||||
|
'';
|
||||||
|
trackSelf = mkEnableOption ''
|
||||||
|
Also track yourself.
|
||||||
|
'';
|
||||||
|
showSeconds = mkEnableOption ''
|
||||||
|
Show seconds in the timer.
|
||||||
|
'';
|
||||||
|
format = mkOption {
|
||||||
|
type = enum ["stopwatch" "human"];
|
||||||
|
default = "human";
|
||||||
|
description = ''
|
||||||
|
Compact or human readable format:
|
||||||
|
- stopwatch: 30:23:00:42
|
||||||
|
- human: 30d 23h 00m 42s
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
watchLargeGuilds = mkEnableOption ''
|
||||||
|
Track users in large guild. Warning this may cause lag if your in a lot
|
||||||
|
of guilds with active voice users.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
AltKrispSwitch.enabled = mkEnableOption ''
|
||||||
|
Makes the Noise Suppression Popout switch between None and Krisp instead
|
||||||
|
of Krisp and Strandard.
|
||||||
|
'';
|
||||||
|
AlwaysAnimate = {
|
||||||
|
enable = mkEnableOption ''
|
||||||
|
Animates anything that can be animated.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
AlwaysExpandRoles = {
|
||||||
|
enabled = mkEnableOption "Always expand the role list in profile popouts.";
|
||||||
|
hideArrow = mkEnableOption "Hide Arrows.";
|
||||||
|
};
|
||||||
|
AlwaysTrust = {
|
||||||
|
enabled = mkEnableOption ''
|
||||||
|
Remove the untrusted domain and suspicious file popup.
|
||||||
|
'';
|
||||||
|
domain = mkEnableOption ''
|
||||||
|
Remove the untrusted domain popup when opening links.
|
||||||
|
'';
|
||||||
|
file = mkEnableOption ''
|
||||||
|
Remove the "Potentially Dangerous Download" popup when opening links.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
AmITyping.enabled = mkEnableOption "Shows you if other people can see you typing.";
|
||||||
|
Anammox = {
|
||||||
|
enabled = mkEnableOption ''
|
||||||
|
A microbial process that plays an important part in the nitrogen cycle.
|
||||||
|
Hide various discord nitro excusive features.
|
||||||
|
'';
|
||||||
|
dms = mkEnableOption "Remove shops above DMs list";
|
||||||
|
billing = mkEnableOption "Remove billings settings";
|
||||||
|
gift = mkEnableOption "Remove gift button";
|
||||||
|
emojiList = mkEnableOption "Remove unavailable catagories from the emoji picker";
|
||||||
|
};
|
||||||
|
AnonymiseFileNames = {
|
||||||
|
enabled = mkEnableOption "Anonymise uploaded file names";
|
||||||
|
anonymiseByDefault = mkEnableOption "Whether to anonymise file names by default";
|
||||||
|
method = mkOption {
|
||||||
|
type = enum ["random characters" "consistant" "timestamp"];
|
||||||
|
default = "random characters";
|
||||||
|
apply = mkEquibopSelect {
|
||||||
|
"random characters" = 0;
|
||||||
|
"consistent" = 1;
|
||||||
|
"timestamp" = 2;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
randomizedLength = mkOption {
|
||||||
|
type = int;
|
||||||
|
default = 7;
|
||||||
|
description = "Random character length.";
|
||||||
|
};
|
||||||
|
consistent = mkOption {
|
||||||
|
type = str;
|
||||||
|
default = "image";
|
||||||
|
description = "Consistant filename.";
|
||||||
|
# doesn't appear to be an option you can change
|
||||||
|
readOnly = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
AtSomeone.enabled = mkEnableOption "Mention someone randomly.";
|
||||||
|
BANger = {
|
||||||
|
enabled = mkEnableOption "Replaces the GIF i nthe ban dialogue with a custom one.";
|
||||||
|
source = mkOption {
|
||||||
|
type = str;
|
||||||
|
default = "";
|
||||||
|
description = "Source to replace ban GIF with (video or GIF).";
|
||||||
|
example = "https://i.imgur.com/wp5q52C.mp4";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
BannersEverywhere = {
|
||||||
|
enabled = mkEnableOption "Display banners in the member list.";
|
||||||
|
animate = mkEnableOption "Animate banners.";
|
||||||
|
};
|
||||||
|
BetterActivities = {
|
||||||
|
enabled = mkEnableOption ''
|
||||||
|
Shows activity icons in the member list and allows showing all activities.
|
||||||
|
'';
|
||||||
|
memberList = mkEnableOption "Show activity icons in the member list";
|
||||||
|
iconSize = mkOption {
|
||||||
|
type = int;
|
||||||
|
default = 15;
|
||||||
|
description = "Size of the activity icons.";
|
||||||
|
};
|
||||||
|
specialFirst = mkEnableOption "Show special activities first (Currently Spotify and Twitch).";
|
||||||
|
renderGifs = mkEnableOption "Allow rendering GIFs.";
|
||||||
|
showAppDescription = mkEnableOption "Show application descriptions in the activity tooltip.";
|
||||||
|
userPopout = mkEnableOption "Show all activities in the profile popout/sidebar.";
|
||||||
|
allActivitiesStyle = mkOption {
|
||||||
|
type = enum ["corousel" "list"];
|
||||||
|
default = "corousel";
|
||||||
|
description = "Style for showing all activities";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
BetterAudioPlayer = {
|
||||||
|
enabled = mkEnableOption ''
|
||||||
|
Adds a spectograph and oscilloscope visualizer to audio attachment players.
|
||||||
|
'';
|
||||||
|
oscilloscope = mkEnableOption "Enable oscilloscope visualizer.";
|
||||||
|
spectograph = mkEnableOption "Enable spectograph visualizer.";
|
||||||
|
oscilloscopeSolidColor = mkEnableOption "Use colid color for oscilloscope.";
|
||||||
|
oscilloscopeColor = mkOption {
|
||||||
|
# not 100% sure if a hex color value can be set via json here
|
||||||
|
type = rgbDecimal;
|
||||||
|
default = "255, 255, 255";
|
||||||
|
description = "RGB Color for the oscilloscope.";
|
||||||
|
example = "10, 200, 130";
|
||||||
|
};
|
||||||
|
spectographSolidColor = mkEnableOption "Use solid color for spectograph.";
|
||||||
|
spectographColor = mkOption {
|
||||||
|
type = rgbDecimal;
|
||||||
|
default = "33, 150, 243";
|
||||||
|
example = "10, 200, 130";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
BetterBanReasons = {
|
||||||
|
enabled = mkEnableOption ''
|
||||||
|
Create custom reasons to use in the Discord Ban modal, and/or
|
||||||
|
show a test input by default instead of the options.
|
||||||
|
'';
|
||||||
|
reasons = mkOption {
|
||||||
|
type = listOf str;
|
||||||
|
default = [];
|
||||||
|
description = "List of ban reasons";
|
||||||
|
example = [
|
||||||
|
"uses nix"
|
||||||
|
"arch user"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
textInputDefault = mkEnableOption ''
|
||||||
|
Shows a text input instead of a select menu by default. (Equivalent to clicking the "Other" option).
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
BetterFolders = {
|
||||||
|
enabled = mkEnableOption ''
|
||||||
|
Shows server folders on dedicated sidebar and adds folder related improvements.
|
||||||
|
'';
|
||||||
|
sidebar = mkEnableOption "Display servers from folder on dedicated sidebar.";
|
||||||
|
sidebarAnim = mkEnableOption "Animate opening the folder sidebar.";
|
||||||
|
closeAllFolders = mkEnableOption "Close all folders when selecting a server not in a folder.";
|
||||||
|
closeOthers = mkEnableOption "Close other folders when opening a folder.";
|
||||||
|
forceOpen = mkEnableOption "Force a folder to open when switching to a server of that folder.";
|
||||||
|
keepIcons = mkEnableOption ''
|
||||||
|
Keep showing guild icons in the primary guild bar folder when it's open
|
||||||
|
in the BetterFolders sidebar.
|
||||||
|
'';
|
||||||
|
showFoldersIcon = mkOption {
|
||||||
|
type = enum ["never" "always" "when more than one folder is expanded"];
|
||||||
|
default = "always";
|
||||||
|
description = ''
|
||||||
|
Show the folder icon above the folder guilds in the BetterFolders sidebar.
|
||||||
|
Available options:
|
||||||
|
- "never"
|
||||||
|
- "always"
|
||||||
|
- "when more than one folder is expanded"
|
||||||
|
'';
|
||||||
|
apply = mkEquibopSelect {
|
||||||
|
"never" = 0;
|
||||||
|
"always" = 1;
|
||||||
|
"when more than one folder is expanded" = 2;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
BetterGifAltText = mkEnableOption ''
|
||||||
|
Change GIF alt text from simply being 'GIF' to containing the gif tags/filename.
|
||||||
|
'';
|
||||||
|
BetterGifPicker = mkEnableOption "Makes the GIF picker open the favourite category by default";
|
||||||
|
BetterInvites = mkEnableOption ''
|
||||||
|
See invites expiration date, view inviter profile and preview discoverable servers before joining
|
||||||
|
by clicking their name.
|
||||||
|
'';
|
||||||
|
BetterNotesBox = {
|
||||||
|
enabled = mkEnableOption "Hide notes or disable spellcheck.";
|
||||||
|
hide = mkEnableOption "Hide notes.";
|
||||||
|
noSpellCheck = mkEnableOption "Disable spellcheck in notes";
|
||||||
|
};
|
||||||
|
BetterQuickReact = {
|
||||||
|
enabled = mkEnableOption "Improves the quick react buttons in the message context menu";
|
||||||
|
frequentEmojis = mkEnableOption "Use frequently used emojis instead of favorite emojis";
|
||||||
|
rows = mkOption {
|
||||||
|
type = numbers.between 1 16;
|
||||||
|
default = 2;
|
||||||
|
description = "Rows of quick reactions to display. Number between 1-16";
|
||||||
|
example = 4;
|
||||||
|
};
|
||||||
|
columns = mkOption {
|
||||||
|
type = numbers.between 1 12;
|
||||||
|
default = 4;
|
||||||
|
description = "Columns of quick reactions to display. Number betwen 1-12";
|
||||||
|
example = 6;
|
||||||
|
};
|
||||||
|
compactMode = mkEnableOption ''
|
||||||
|
Scales the buttons to 75% of their original scale, whilst increasing the inner emoji to 125% scale.
|
||||||
|
Emojis will be 93.75% of the original size. Reccomended to have a minimum of 5 columns.
|
||||||
|
'';
|
||||||
|
scroll = mkEnableOption "Enable scrolling the list of emojis";
|
||||||
|
};
|
||||||
|
BetterRoleContext = {
|
||||||
|
enabled = mkEnableOption ''
|
||||||
|
Adds options to copy role color / edit role / view role icon when right clicking roles in
|
||||||
|
in the user profile
|
||||||
|
'';
|
||||||
|
roleIconFileFormat = mkOption {
|
||||||
|
type = enum ["webp" "png" "jpg"];
|
||||||
|
default = "png";
|
||||||
|
description = "File formate to use when viewing role icons";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
BetterRoleDot = {
|
||||||
|
enabled = mkEnableOption ''
|
||||||
|
Copy role colour on RoleDot (accessibility setting) click. Also allows using both
|
||||||
|
RoleDot and coloured names simultaneously.
|
||||||
|
'';
|
||||||
|
bothStyles = mkEnableOption "Show both role dot and coloured names";
|
||||||
|
copyRoleColorInProfilePopout = mkEnableOption "Allow click on role dot in profile popout to copy role color";
|
||||||
|
};
|
||||||
|
BetterSession = {
|
||||||
|
enabled = mkEnableOption ''
|
||||||
|
Enhances the sessions (devices) menu. Allows you to view exact timestamps, give each session a
|
||||||
|
custom name, and receive notifications about new sessions.
|
||||||
|
'';
|
||||||
|
backgroundCheck = mkEnableOption ''
|
||||||
|
Check for new sessions in the background, and display notifications when they are detected.
|
||||||
|
'';
|
||||||
|
checkInterval = mkOption {
|
||||||
|
type = int;
|
||||||
|
default = 20;
|
||||||
|
description = "How often to check for new sessions in the background (if enabled), in minutes.";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
BetterSettings = {
|
||||||
|
enabled = mkEnableOption "Enhances your settings-menu-opening experience.";
|
||||||
|
disableFade = mkEnableOption "Disable the crossfade animation.";
|
||||||
|
organizeMenu = mkEnableOption "Organizes the settings cog context menu into categories.";
|
||||||
|
eagerLoad = mkEnableOption "Removes the loading delay when opening the menu for the first time.";
|
||||||
|
};
|
||||||
|
BetterUploadButton.enabled = mkEnableOption "Upload with a single click, open menu with right click";
|
||||||
|
BetterUserArea.enabled = mkEnableOption ''
|
||||||
|
Reworks the user area styling to fit more buttons and overall look nicer
|
||||||
|
'';
|
||||||
|
BetterStreamPreview.enabled = mkEnableOption "Allows you to enlarge stream previews";
|
||||||
|
BlockKeywords = {
|
||||||
|
enabled = mkEnableOption ''
|
||||||
|
Blocks messages containing specific user-defined keywords, as if the user sending them was blocked.
|
||||||
|
'';
|
||||||
|
blockedWords = mkOption {
|
||||||
|
type = str;
|
||||||
|
default = "";
|
||||||
|
description = "Comma-seperated list of words to block.";
|
||||||
|
example = "arch,home-manager";
|
||||||
|
};
|
||||||
|
useRegex = mkEnableOption "Use each value as a regular expression when checking message content (advanced)";
|
||||||
|
caseSensitive = mkEnableOption "Whether to use a case sensitive search or not.";
|
||||||
|
ignoreBlockedMessages = mkEnableOption "Completely ignores (recent) new messages bar";
|
||||||
|
};
|
||||||
|
BlockKrisp.enabled = mkEnableOption "Prevent Krist from loading";
|
||||||
|
BlurNSFW = {
|
||||||
|
enabled = mkEnableOption "Blur attachments in NSFW channels until hovered.";
|
||||||
|
blurAmount = mkOption {
|
||||||
|
type = int;
|
||||||
|
default = 10;
|
||||||
|
description = "Blur amount";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
BypassStatus = {
|
||||||
|
enabled = mkEnableOption ''
|
||||||
|
Still get notifications from specific sources when in do not disturb mode.
|
||||||
|
Right-click on users/channels/guilds to set them to bypass do not disturb mode.
|
||||||
|
'';
|
||||||
|
guilds = mkOption {
|
||||||
|
type = listOf str;
|
||||||
|
default = [];
|
||||||
|
description = ''
|
||||||
|
Guilds to let bypass (notified when pinged anywhere in guild).
|
||||||
|
List of comma seperated guild IDs.
|
||||||
|
'';
|
||||||
|
example = [
|
||||||
|
"123451234512345123"
|
||||||
|
"456456456456456456"
|
||||||
|
];
|
||||||
|
apply = listToString ",";
|
||||||
|
};
|
||||||
|
channels = mkOption {
|
||||||
|
type = listOf str;
|
||||||
|
default = [];
|
||||||
|
description = ''
|
||||||
|
channels to let bypass (notified when pinged anywhere in channel).
|
||||||
|
List of .
|
||||||
|
'';
|
||||||
|
example = [
|
||||||
|
"123451234512345123"
|
||||||
|
"456456456456456456"
|
||||||
|
];
|
||||||
|
apply = listToString ",";
|
||||||
|
};
|
||||||
|
users = mkOption {
|
||||||
|
type = listOf str;
|
||||||
|
default = [];
|
||||||
|
description = ''
|
||||||
|
users to let bypass (notified when pinged anywhere in guild).
|
||||||
|
List of comma seperated user IDs.
|
||||||
|
'';
|
||||||
|
example = [
|
||||||
|
"123451234512345123"
|
||||||
|
"456456456456456456"
|
||||||
|
];
|
||||||
|
apply = listToString ",";
|
||||||
|
};
|
||||||
|
notificationSound = mkEnableOption "Whether the notification sound should be played";
|
||||||
|
statusToUse = mkOption {
|
||||||
|
type = enum ["dnd" "invisible" "idle"];
|
||||||
|
default = "dnd";
|
||||||
|
description = "Status to use for whitelist.";
|
||||||
|
};
|
||||||
|
allowOutsideOfDm = mkEnableOption ''
|
||||||
|
Allow selected users to bypass status outside of DMs too
|
||||||
|
(acts like a channel/guild bypass, but it's for all messages sent by the selected users).
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
CallTimer = {
|
||||||
|
enabled = mkEnableOption "Adds a timer to vcs.";
|
||||||
|
format = mkOption {
|
||||||
|
type = enum ["human" "stopwatch"];
|
||||||
|
default = "human";
|
||||||
|
description = "The timer format.";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
ChannelBadges = {
|
||||||
|
enabled = mkEnableOption "Adds badges to channels based on their type.";
|
||||||
|
oneBadgePerChannel = mkEnableOption "Show only one badge per channel.";
|
||||||
|
showTextBadge = mkEnableOption "Show Text badge";
|
||||||
|
showVoiceBadge = mkEnableOption "Show Voice badge";
|
||||||
|
showCategoryBadge = mkEnableOption "Show Category badge";
|
||||||
|
showDirectoryBadge = mkEnableOption "Show Directory badge";
|
||||||
|
showAnnouncementThreadBadge = mkEnableOption "Show Announcement Thread badge";
|
||||||
|
showPublicThreadBadge = mkEnableOption "Show Public Thread badge";
|
||||||
|
showPrivateThreadBadge = mkEnableOption "Show Private Thread badge";
|
||||||
|
showStageBadge = mkEnableOption "Show Stage badge";
|
||||||
|
showAnnouncementBadge = mkEnableOption "Show Announcement badge";
|
||||||
|
showForumBadge = mkEnableOption "Show Forum badge";
|
||||||
|
showMediaBadge = mkEnableOption "Show Media badge";
|
||||||
|
showNSFWBadge = mkEnableOption "Show NSFW badge";
|
||||||
|
showLockedBadge = mkEnableOption "Show Locked badge";
|
||||||
|
showRulesBadge = mkEnableOption "Show Rules badge";
|
||||||
|
showUnknownBadge = mkEnableOption "Show Unknown badge";
|
||||||
|
textBadgeLabel = mkLabelOption "Text";
|
||||||
|
voiceBadgeLabel = mkLabelOption "Voice";
|
||||||
|
categoryBadgeLabel = mkLabelOption "Category";
|
||||||
|
announcementBadgeLabel = mkLabelOption "News";
|
||||||
|
announcementThreadBadgeLabel = mkLabelOption "News Thread";
|
||||||
|
publicThreadBadgeLabel = mkLabelOption "Thread";
|
||||||
|
privateThreadBadgeLabel = mkLabelOption "Private Thread";
|
||||||
|
stageBadgeLabel = mkLabelOption "Stage";
|
||||||
|
directoryBadgeLabel = mkLabelOption "Directory";
|
||||||
|
forumBadgeLabel = mkLabelOption "Forum";
|
||||||
|
mediaBadgeLabel = mkLabelOption "Media";
|
||||||
|
nsfwBadgeLabel = mkLabelOption "NSFW";
|
||||||
|
lockedBadgeLabel = mkLabelOption "Locked";
|
||||||
|
rulesBadgeLabel = mkLabelOption "Rules";
|
||||||
|
unknownBadgeLabel = mkLabelOption "Unknown";
|
||||||
|
lockedBadgeColor = mkHexColorOption "Locked badge";
|
||||||
|
rulesBadgeColor = mkHexColorOption "Rules badge";
|
||||||
|
unknownBadgeColor = mkHexColorOption "Unknown badge";
|
||||||
|
nsfwBadgeColor = mkHexColorOption "NSFW badge";
|
||||||
|
mediaBadgeColor = mkHexColorOption "Media badge";
|
||||||
|
forumBadgeColor = mkHexColorOption "Forum badge";
|
||||||
|
directoryBadgeColor = mkHexColorOption "Directory badge";
|
||||||
|
stageBadgeColor = mkHexColorOption "Stage badge";
|
||||||
|
privateThreadBadgeColor = mkHexColorOption "Private Thread badge";
|
||||||
|
publicThreadBadgeColor = mkHexColorOption "Public Thread badge";
|
||||||
|
announcementThreadBadgeColor = mkHexColorOption "Announcement Thread badge";
|
||||||
|
announcementBadgeColor = mkHexColorOption "Announcement badge";
|
||||||
|
categoryBadgeColor = mkHexColorOption "Category badge";
|
||||||
|
voiceBadgeColor = mkHexColorOption "Voice badge";
|
||||||
|
textBadgeColor = mkHexColorOption "Text Badge";
|
||||||
|
};
|
||||||
|
# doesn't seem to work for me. May require window decorations?
|
||||||
|
ChannelTabs.enabled = mkEnableOption ''
|
||||||
|
Group our commonly visited channels in tabs. Warning: this doesnt appear to be working.
|
||||||
|
'';
|
||||||
|
CharacterCounter = {
|
||||||
|
enabled = mkEnableOption "Adds a character counter to the chat input.";
|
||||||
|
colorEffects = mkEnableOption "Turn on or off color effects for getting close to the character limit";
|
||||||
|
position = mkEnableOption "Move the character counter to the left side of the chat input";
|
||||||
|
};
|
||||||
|
CleanChannelName.enabled = mkEnableOption "Remove all emoji and decor from channel names";
|
||||||
|
ClearURLs.enabled = mkEnableOption "Remove tracking garbage from URLs";
|
||||||
|
ClientSideBlock = {
|
||||||
|
enabled = mkEnableOption "Allows you to locally hide almost all content from any user";
|
||||||
|
usersToBlock = mkOption {
|
||||||
|
type = listOf str;
|
||||||
|
default = [];
|
||||||
|
description = "List of User IDs to block";
|
||||||
|
example = [
|
||||||
|
"123456789"
|
||||||
|
"987654321"
|
||||||
|
];
|
||||||
|
apply = listToString ", ";
|
||||||
|
};
|
||||||
|
hideBlockedUser = mkEnableOption "Should blocked users also be hidden everywhere.";
|
||||||
|
hideBlockedMessages = mkEnableOption "Should messages from blocked users be hidden fully.";
|
||||||
|
hideEmptyRoles = mkEnableOption "Should role headers be hidden if all of their member are blocked.";
|
||||||
|
blockedReplyDisplay = mkOption {
|
||||||
|
type = enum ["displayText" "hideReply"];
|
||||||
|
default = "displayText";
|
||||||
|
description = ''
|
||||||
|
What should display instead of the message when someone replies to someone you have hidden.
|
||||||
|
- "displayText": Display text saying a hidden message was replied to.
|
||||||
|
- "hideReply": Literally nothing
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
guildBlackList = mkOption {
|
||||||
|
type = listOf str;
|
||||||
|
default = [];
|
||||||
|
description = "List of guild IDs to disable functionality in";
|
||||||
|
apply = listToString ", ";
|
||||||
|
};
|
||||||
|
guildWhiteList = mkOption {
|
||||||
|
type = listOf str;
|
||||||
|
default = [];
|
||||||
|
description = "List of guild IDs to enable functionality in";
|
||||||
|
apply = listToString ", ";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
ClientTheme = {
|
||||||
|
enabled = mkEnableOption "Recreation of the old client theme experiment. Add color to your Discord client theme";
|
||||||
|
color = mkOption {
|
||||||
|
type = strMatching "[[:xdigit:]]{6}";
|
||||||
|
description = "Themes Color";
|
||||||
|
default = "282828";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
ColorSighted.enabled = mkEnableOption "Removes the colorblind-friendly icons from statuses, just like 2015-2017 Discord";
|
||||||
|
CommandPalette = {
|
||||||
|
enabled = mkEnableOption "Allows you to navigate the UI with a keyboard.";
|
||||||
|
hotkey = mkOption {
|
||||||
|
# TODO: Regex this
|
||||||
|
type = listOf str;
|
||||||
|
default = [
|
||||||
|
"control"
|
||||||
|
"shift"
|
||||||
|
"p"
|
||||||
|
];
|
||||||
|
description = "HotKey to toggle the command palette.";
|
||||||
|
example = [
|
||||||
|
"control"
|
||||||
|
"h"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
ConsoleJanitor = {
|
||||||
|
enabled = mkEnableOption "Disables annoying console messages/errors";
|
||||||
|
disableLoggers = mkEnableOption "Disables Discord loggers";
|
||||||
|
disableSpotifyLoggers = mkEnableOption "Disable the Spotify logger, which leaks account information and access token";
|
||||||
|
whitlistedLoggers = mkOption {
|
||||||
|
type = listOf str;
|
||||||
|
default = [
|
||||||
|
"GatewaySocket"
|
||||||
|
"Routing/Utils"
|
||||||
|
];
|
||||||
|
description = "List of loggers to allow even if others are hidden.";
|
||||||
|
apply = listToString "; ";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
ConsoleShortcuts.enabled = mkEnableOption ''
|
||||||
|
Adds shorter Aliases for many things on the window. Run 'shortcutList' for a list.
|
||||||
|
'';
|
||||||
|
CopyEmojiMarkdown = {
|
||||||
|
enabled = mkEnableOption "Allows you to copy emojis as formatted string (<:blobcatcozy:1026533070955872337>).";
|
||||||
|
copyUnicode = mkEnableOption "Copy the raw unicode character instead of :name: for default emojis.";
|
||||||
|
};
|
||||||
|
CopyFileContents.enabled = mkEnableOption "Adds a button to text file attachments to copy their contents.";
|
||||||
|
CopyUserMention.enabled = mkEnableOption ''
|
||||||
|
Adds a button to copy user's mention on the user context menu, works best with ValidUser.
|
||||||
|
'';
|
||||||
|
CopyUserURLs.enabled = mkEnableOption "Adds a 'Copy User URL' option to the user context menu.";
|
||||||
|
CrashHandler = {
|
||||||
|
enabled = mkBoolOption true "Utility for handling and possibly recovering from chrashes without restart.";
|
||||||
|
attemptToPreventCrashes = mkBoolOption true "Whether to attempt to prevent Discord crashes.";
|
||||||
|
attemptToNavigateToHome = mkEnableOption "Whether to attempt to navigate to the home when preventing Discord crashes.";
|
||||||
|
};
|
||||||
|
CtrlEnterSend = {
|
||||||
|
enabled = mkEnableOption "Use Ctrl+Enter to send messages (customizable).";
|
||||||
|
submitRule = mkOption {
|
||||||
|
type = enum ["ctrl+enter" "shift+enter" "enter"];
|
||||||
|
default = "ctrl+enter";
|
||||||
|
description = ''
|
||||||
|
The way to send a messages.
|
||||||
|
Available options:
|
||||||
|
- "ctrl+enter" (Enter of Shift+Enter for new line) (cmd+enter on macOS)
|
||||||
|
- "shift+enter" (Enter for a new Line)
|
||||||
|
- "enter" (Shift+Enter for new line; Discord default)
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
sendMessageInTheMiddleOfACodeBlock = mkEnableOption "Whether to send a message in the middle of a code block.";
|
||||||
|
};
|
||||||
|
CustomIdle = {
|
||||||
|
enabled = mkEnableOption "Allows you to set the time before Discord goes idle (or disable auto-idle)";
|
||||||
|
idleTimeout = {
|
||||||
|
type = numbers.between 0 60;
|
||||||
|
default = 20;
|
||||||
|
description = "Minutes before Discord goes idle (0 to disable auto-idle). 0.0 - 60.0";
|
||||||
|
};
|
||||||
|
remainInIdle = mkEnableOption "When you come back to Discord, remain idle until you confirm you want to go online";
|
||||||
|
};
|
||||||
|
CustomSounds.enabled = mkEnableOption "Replace Discord's sounds with your own, custom sounds must be defined via client";
|
||||||
|
CustomTimestamps = let
|
||||||
|
mkTimestampOption = default: description:
|
||||||
|
mkOption {
|
||||||
|
type = str;
|
||||||
|
inherit default description;
|
||||||
|
};
|
||||||
|
in {
|
||||||
|
enabled = mkEnableOption ''
|
||||||
|
Custom timestamps on mesages and tooltips.
|
||||||
|
See <https://momentjs.com/docs/#/displaying/format/> for documentation on formatting.
|
||||||
|
'';
|
||||||
|
cozyFormat = mkTimestampOption "[calander]" "Time format to use in messages on cozy mode.";
|
||||||
|
compactFormat = mkTimestampOption "LT" "Time format on compact mode and hovering messages.";
|
||||||
|
tooltipFormat = mkTimestampOption "LLLL • [relative]" "Time format to use on tooltips.";
|
||||||
|
sameDayFormat = mkTimestampOption "HH:mm:ss" "[calander] format for today.";
|
||||||
|
lastDayFormat = mkTimestampOption "[yesterday] HH:mm:ss" "[calander] format for yesterday.";
|
||||||
|
lastWeekFormat = mkTimestampOption "ddd DD.MM.YYYY HH:mm:ss" "[calander] format for last week.";
|
||||||
|
sameElseFormat = mkTimestampOption "ddd DD.MM.YYYY HH:mm:ss" "[calander] format for older dates.";
|
||||||
|
};
|
||||||
|
# why weebs, why
|
||||||
|
CuteAnimeBoys.enabled = mkEnableOption "Add a command to send cute anime boys in the chat";
|
||||||
|
CuteNekos.enabled = mkEnableOption "Send Nekos to others";
|
||||||
|
CutePats.enabled = mkEnableOption "Sending head pats.";
|
||||||
|
DeadMembers.enabled = mkEnableOption "Shows when the sender of a message has left the guild.";
|
||||||
|
Dearrow = {
|
||||||
|
enabled = mkEnableOption "Makes YouTube embed titles and thumbnails less sensationalist, powered by Dearrow.";
|
||||||
|
hideButton = mkEnableOption "Hides the Dearrow button from Youtube embeds.";
|
||||||
|
replaceElements = mkOption {
|
||||||
|
type = enum ["everything" "titles" "thumbnails"];
|
||||||
|
default = "everything";
|
||||||
|
description = ''
|
||||||
|
Choose which elements of the embed will be replaced.
|
||||||
|
Available options:
|
||||||
|
- "everything"
|
||||||
|
- "titles"
|
||||||
|
- "thumbnails"
|
||||||
|
'';
|
||||||
|
apply = mkEquibopSelect {
|
||||||
|
"everything" = 0;
|
||||||
|
"titles" = 1;
|
||||||
|
"thumbnails" = 2;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
dearrowByDefault = mkEnableOption "Dearrow videos automatically";
|
||||||
|
};
|
||||||
|
DecodeBase64 = {
|
||||||
|
enabled = mkEnableOption "Decode base64 content of any message and copy the decoded content.";
|
||||||
|
clickMethod = mkOption {
|
||||||
|
type = enum ["Left" "Right"];
|
||||||
|
default = "Left";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
config = mkIf cfg.enable {
|
||||||
|
# test file until module is complete
|
||||||
|
xdg.configFile."equibop/test.json".text = builtins.toJSON cfg.settings;
|
||||||
|
|
||||||
|
ooknet.equicord = {
|
||||||
|
plugins = {
|
||||||
|
CommandPallete.enabled = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -4,5 +4,8 @@
|
||||||
lspkind.enable = true;
|
lspkind.enable = true;
|
||||||
lspSignature.enable = true;
|
lspSignature.enable = true;
|
||||||
trouble = {enable = true;};
|
trouble = {enable = true;};
|
||||||
|
null-ls = {
|
||||||
|
enable = true;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,19 @@
|
||||||
vim = {
|
vim = {
|
||||||
languages.markdown = {
|
languages.markdown = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
vale.enable = true;
|
||||||
|
ltex.enable = true;
|
||||||
extensions = {
|
extensions = {
|
||||||
render-markdown-nvim = {
|
render-markdown-nvim = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
setupOpts = {
|
||||||
|
heading = {
|
||||||
|
border = true;
|
||||||
|
width = "block";
|
||||||
|
left_pad = 3;
|
||||||
|
right_pad = 4;
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,11 @@
|
||||||
useSystemClipboard = true;
|
useSystemClipboard = true;
|
||||||
autopairs.nvim-autopairs.enable = true;
|
autopairs.nvim-autopairs.enable = true;
|
||||||
hideSearchHighlight = true;
|
hideSearchHighlight = true;
|
||||||
spellcheck.enable = true;
|
|
||||||
theme = {
|
theme = {
|
||||||
enable = false;
|
enable = false;
|
||||||
};
|
};
|
||||||
|
spellcheck = {
|
||||||
|
enable = true;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,31 @@
|
||||||
{
|
{hozen, ...}: let
|
||||||
|
inherit (hozen) color;
|
||||||
|
in {
|
||||||
vim.gruvbox-material = {
|
vim.gruvbox-material = {
|
||||||
enable = true;
|
enable = true;
|
||||||
contrast = "medium";
|
contrast = "medium";
|
||||||
italics = false;
|
italics = false;
|
||||||
transparent = false;
|
transparent = false;
|
||||||
extraConfig =
|
additionalHighlights = {
|
||||||
# lua
|
RenderMarkdownH1Bg = {bg = "#${color.layout.body}";};
|
||||||
''
|
RenderMarkdownH2Bg = {bg = "#${color.layout.body}";};
|
||||||
local g_colors = require("gruvbox-material.colors")
|
RenderMarkdownH3Bg = {bg = "#${color.layout.body}";};
|
||||||
local colors = g_colors.get(vim.o.background, "soft")
|
RenderMarkdownH4Bg = {bg = "#${color.layout.body}";};
|
||||||
|
RenderMarkdownH5Bg = {bg = "#${color.layout.body}";};
|
||||||
|
RenderMarkdownH6Bg = {bg = "#${color.layout.body}";};
|
||||||
|
"@markup.heading.1" = {
|
||||||
|
fg = "#${color.green.base}";
|
||||||
|
bold = true;
|
||||||
|
};
|
||||||
|
"@markup.heading.2" = {
|
||||||
|
fg = "#${color.blue.base}";
|
||||||
|
bold = true;
|
||||||
|
};
|
||||||
|
|
||||||
-- Noice
|
NoiceCmdlinePopupBorder = {fg = "#${color.border.active}";};
|
||||||
vim.api.nvim_set_hl(0, "NoiceCmdlinePopupBorderHelp", { fg = colors.yellow })
|
NoiceCmdlinePopupBorderHelp = {fg = "#${color.yellow.base}";};
|
||||||
vim.api.nvim_set_hl(0, "NoiceCmdlinePopupBorder", { fg = colors.grey1 })
|
NoiceCmdlineIcon = {fg = "#${color.green.base}";};
|
||||||
vim.api.nvim_set_hl(0, "NoiceCmdlineIcon", { fg = colors.green })
|
NoiceCmdLinePopupTitle = {fg = "#${color.typography.text}";};
|
||||||
vim.api.nvim_set_hl(0, "NoiceCmdLinePopupTitle", { fg = colors.grey1 })
|
};
|
||||||
'';
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,8 @@
|
||||||
imports = [
|
imports = [
|
||||||
./gruvbox-material
|
./gruvbox-material
|
||||||
./telescope
|
./telescope
|
||||||
./obsidian
|
|
||||||
./theme
|
./theme
|
||||||
|
./notes
|
||||||
|
./languages
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,105 @@
|
||||||
...
|
...
|
||||||
}: let
|
}: let
|
||||||
inherit (lib) mkOption mkIf boolToString;
|
inherit (lib) mkOption mkIf boolToString;
|
||||||
inherit (lib.types) bool enum lines;
|
inherit (lib.types) bool enum lines nullOr str submodule attrsOf;
|
||||||
inherit (lib.nvim.dag) entryAfter;
|
inherit (lib.nvim.dag) entryBefore;
|
||||||
|
inherit (lib.nvim.lua) toLuaObject;
|
||||||
|
|
||||||
|
# hack to get around nvf's handling of prefixed @ in toLuaObject
|
||||||
|
wrapHighlights = highlights:
|
||||||
|
lib.mapAttrs' (
|
||||||
|
name: value:
|
||||||
|
if lib.hasPrefix "@" name
|
||||||
|
then lib.nameValuePair "hl_${name}" value
|
||||||
|
else lib.nameValuePair name value
|
||||||
|
)
|
||||||
|
highlights;
|
||||||
|
|
||||||
|
highlightOpts = submodule {
|
||||||
|
options = {
|
||||||
|
# https://neovim.io/doc/user/api.html#nvim_set_hl()
|
||||||
|
fg = mkOption {
|
||||||
|
type = nullOr str;
|
||||||
|
default = null;
|
||||||
|
description = "Foreground color";
|
||||||
|
};
|
||||||
|
bg = mkOption {
|
||||||
|
type = nullOr str;
|
||||||
|
default = null;
|
||||||
|
description = "Background color";
|
||||||
|
};
|
||||||
|
sp = mkOption {
|
||||||
|
type = nullOr str;
|
||||||
|
default = null;
|
||||||
|
description = "SP color";
|
||||||
|
};
|
||||||
|
blend = mkOption {
|
||||||
|
type = nullOr bool;
|
||||||
|
default = null;
|
||||||
|
description = "Blend attribute";
|
||||||
|
};
|
||||||
|
bold = mkOption {
|
||||||
|
type = nullOr bool;
|
||||||
|
default = null;
|
||||||
|
description = "Italic attribute";
|
||||||
|
};
|
||||||
|
standout = mkOption {
|
||||||
|
type = nullOr bool;
|
||||||
|
default = null;
|
||||||
|
description = "Standout attribute";
|
||||||
|
};
|
||||||
|
underline = mkOption {
|
||||||
|
type = nullOr bool;
|
||||||
|
default = null;
|
||||||
|
description = "underline attribute";
|
||||||
|
};
|
||||||
|
undercurl = mkOption {
|
||||||
|
type = nullOr bool;
|
||||||
|
default = null;
|
||||||
|
description = "Undercurl attribute";
|
||||||
|
};
|
||||||
|
underdouble = mkOption {
|
||||||
|
type = nullOr bool;
|
||||||
|
default = null;
|
||||||
|
description = "Underdouble attribute";
|
||||||
|
};
|
||||||
|
underdotted = mkOption {
|
||||||
|
type = nullOr bool;
|
||||||
|
default = null;
|
||||||
|
description = "Underdotted attribute";
|
||||||
|
};
|
||||||
|
underdashed = mkOption {
|
||||||
|
type = nullOr bool;
|
||||||
|
default = null;
|
||||||
|
description = "Underdashed attribute";
|
||||||
|
};
|
||||||
|
strikethrough = mkOption {
|
||||||
|
type = nullOr bool;
|
||||||
|
default = null;
|
||||||
|
description = "Strikethrough attribute";
|
||||||
|
};
|
||||||
|
italic = mkOption {
|
||||||
|
type = nullOr bool;
|
||||||
|
default = null;
|
||||||
|
description = "Bold attribute";
|
||||||
|
};
|
||||||
|
reverse = mkOption {
|
||||||
|
type = nullOr bool;
|
||||||
|
default = null;
|
||||||
|
description = "Reverse attribute";
|
||||||
|
};
|
||||||
|
nocombine = mkOption {
|
||||||
|
type = nullOr bool;
|
||||||
|
default = null;
|
||||||
|
description = "Nocombine attribute";
|
||||||
|
};
|
||||||
|
link = mkOption {
|
||||||
|
type = nullOr str;
|
||||||
|
default = null;
|
||||||
|
description = "Link attribute";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
cfg = config.vim.gruvbox-material;
|
cfg = config.vim.gruvbox-material;
|
||||||
in {
|
in {
|
||||||
|
|
@ -45,13 +142,18 @@ in {
|
||||||
type = lines;
|
type = lines;
|
||||||
description = "Additional lua configuration after";
|
description = "Additional lua configuration after";
|
||||||
};
|
};
|
||||||
|
additionalHighlights = mkOption {
|
||||||
|
type = attrsOf highlightOpts;
|
||||||
|
default = {};
|
||||||
|
description = "Additional highlight groups to be applied after theme setup.";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config = mkIf cfg.enable {
|
config = mkIf cfg.enable {
|
||||||
vim = {
|
vim = {
|
||||||
startPlugins = [pkgs.vimPlugins.gruvbox-material-nvim];
|
startPlugins = [pkgs.vimPlugins.gruvbox-material-nvim];
|
||||||
luaConfigRC.theme =
|
luaConfigRC.theme =
|
||||||
entryAfter ["basic"]
|
entryBefore ["pluginConfigs" "lazyConfigs"]
|
||||||
/*
|
/*
|
||||||
lua
|
lua
|
||||||
*/
|
*/
|
||||||
|
|
@ -72,7 +174,14 @@ in {
|
||||||
highlight = ${boolToString cfg.signsHighlight},
|
highlight = ${boolToString cfg.signsHighlight},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
${cfg.extraConfig}
|
|
||||||
|
local extra_highlights = ${toLuaObject (wrapHighlights cfg.additionalHighlights)}
|
||||||
|
for group_name, settings in pairs(extra_highlights) do
|
||||||
|
-- Unwrap our prefixed names back to @ form
|
||||||
|
local actual_name = group_name:gsub("^hl_@", "@")
|
||||||
|
vim.api.nvim_set_hl(0, actual_name, settings)
|
||||||
|
end
|
||||||
|
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
{imports = [./markdown.nix];}
|
||||||
135
outputs/pkgs/ook-vim/modules/plugins/languages/markdown.nix
Normal file
135
outputs/pkgs/ook-vim/modules/plugins/languages/markdown.nix
Normal file
|
|
@ -0,0 +1,135 @@
|
||||||
|
# modules/plugins/vale/default.nix
|
||||||
|
{
|
||||||
|
config,
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}: let
|
||||||
|
inherit (lib.options) mkOption mkEnableOption;
|
||||||
|
inherit (lib.modules) mkIf mkMerge;
|
||||||
|
inherit (lib.types) package enum str;
|
||||||
|
|
||||||
|
languages = [
|
||||||
|
"auto"
|
||||||
|
"ar"
|
||||||
|
"ast-ES"
|
||||||
|
"be-BY"
|
||||||
|
"br-FR"
|
||||||
|
"ca-ES"
|
||||||
|
"ca-ES-valencia"
|
||||||
|
"da-DK"
|
||||||
|
"de"
|
||||||
|
"de-AT"
|
||||||
|
"de-CH"
|
||||||
|
"de-DE"
|
||||||
|
"de-DE-x-simple-language"
|
||||||
|
"el-GR"
|
||||||
|
"en"
|
||||||
|
"en-AU"
|
||||||
|
"en-CA"
|
||||||
|
"en-GB"
|
||||||
|
"en-NZ"
|
||||||
|
"en-US"
|
||||||
|
"en-ZA"
|
||||||
|
"eo"
|
||||||
|
"es"
|
||||||
|
"es-AR"
|
||||||
|
"fa"
|
||||||
|
"fr"
|
||||||
|
"ga-IE"
|
||||||
|
"gl-ES"
|
||||||
|
"it"
|
||||||
|
"ja-JP"
|
||||||
|
"km-KH"
|
||||||
|
"nl"
|
||||||
|
"nl-BE"
|
||||||
|
"pl-PL"
|
||||||
|
"pt"
|
||||||
|
"pt-AO"
|
||||||
|
"pt-BR"
|
||||||
|
"pt-MZ"
|
||||||
|
"pt-PT"
|
||||||
|
"ro-RO"
|
||||||
|
"ru-RU"
|
||||||
|
"sk-SK"
|
||||||
|
"sl-SI"
|
||||||
|
"sv"
|
||||||
|
"ta-IN"
|
||||||
|
"tl-PH"
|
||||||
|
"uk-UA"
|
||||||
|
"zh-CN"
|
||||||
|
];
|
||||||
|
|
||||||
|
cfg = config.vim.languages.markdown;
|
||||||
|
in {
|
||||||
|
options.vim.languages.markdown = {
|
||||||
|
vale = {
|
||||||
|
enable = mkEnableOption "Vale linting support";
|
||||||
|
package = mkOption {
|
||||||
|
type = package;
|
||||||
|
default = pkgs.vale.withStyles (styles: [
|
||||||
|
styles.proselint
|
||||||
|
styles.microsoft
|
||||||
|
styles.write-good
|
||||||
|
styles.readability
|
||||||
|
styles.alex
|
||||||
|
]);
|
||||||
|
description = "Vale package to use";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
ltex = {
|
||||||
|
enable = mkEnableOption "Enable ltex-ls";
|
||||||
|
package = mkOption {
|
||||||
|
type = package;
|
||||||
|
default = pkgs.ltex-ls;
|
||||||
|
};
|
||||||
|
language = mkOption {
|
||||||
|
type = enum languages;
|
||||||
|
default = "en";
|
||||||
|
};
|
||||||
|
modelPath = mkOption {
|
||||||
|
type = str;
|
||||||
|
default = "~/.config/nvf/models/ngrams/";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkMerge [
|
||||||
|
(mkIf cfg.vale.enable {
|
||||||
|
vim.lsp.null-ls = {
|
||||||
|
enable = true;
|
||||||
|
sources.vale-lint =
|
||||||
|
# lua
|
||||||
|
''
|
||||||
|
table.insert(
|
||||||
|
ls_sources,
|
||||||
|
null_ls.builtins.diagnostics.vale.with({
|
||||||
|
command = "${cfg.vale.package}/bin/vale",
|
||||||
|
diagnostics_format = "#{m} [#{c}]"
|
||||||
|
})
|
||||||
|
)
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
})
|
||||||
|
(mkIf cfg.ltex.enable {
|
||||||
|
vim.lsp.lspconfig.enable = true;
|
||||||
|
vim.lsp.lspconfig.sources.ltex-lsp =
|
||||||
|
# lua
|
||||||
|
''
|
||||||
|
lspconfig.ltex.setup{
|
||||||
|
cmd = {"${cfg.ltex.package}/bin/ltex-ls"},
|
||||||
|
capabilities = capabilities;
|
||||||
|
on_attach = default_on_attach;
|
||||||
|
settings = {
|
||||||
|
ltex = {
|
||||||
|
language = "${cfg.ltex.language}",
|
||||||
|
additionalRules = {
|
||||||
|
languageModel = "${cfg.ltex.modelPath}",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
})
|
||||||
|
];
|
||||||
|
}
|
||||||
3
outputs/pkgs/ook-vim/modules/plugins/notes/default.nix
Normal file
3
outputs/pkgs/ook-vim/modules/plugins/notes/default.nix
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
imports = [./obsidian];
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,428 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
config,
|
||||||
|
...
|
||||||
|
}: let
|
||||||
|
inherit (lib) mkOption mkEnableOption;
|
||||||
|
inherit (lib.types) str nullOr bool enum listOf int float attrsOf submodule;
|
||||||
|
inherit (lib.nvim.types) mkPluginSetupOption luaInline;
|
||||||
|
|
||||||
|
# All possible Neovim modes
|
||||||
|
neovimModes = [
|
||||||
|
"n"
|
||||||
|
"no"
|
||||||
|
"nov"
|
||||||
|
"noV"
|
||||||
|
"noCTRL-v"
|
||||||
|
"niI"
|
||||||
|
"niR"
|
||||||
|
"niV"
|
||||||
|
"nt"
|
||||||
|
"ntT"
|
||||||
|
"v"
|
||||||
|
"vs"
|
||||||
|
"V"
|
||||||
|
"Vs"
|
||||||
|
"CTRL-V"
|
||||||
|
"CTRL-Vs"
|
||||||
|
"s"
|
||||||
|
"S"
|
||||||
|
"CTRL-S"
|
||||||
|
"i"
|
||||||
|
"ic"
|
||||||
|
"ix"
|
||||||
|
"R"
|
||||||
|
"Rc"
|
||||||
|
"Rx"
|
||||||
|
"Rv"
|
||||||
|
"Rvc"
|
||||||
|
"Rvx"
|
||||||
|
"c"
|
||||||
|
"cr"
|
||||||
|
"cv"
|
||||||
|
"cvr"
|
||||||
|
"r"
|
||||||
|
"rm"
|
||||||
|
"r?"
|
||||||
|
"!"
|
||||||
|
"t"
|
||||||
|
];
|
||||||
|
|
||||||
|
# Preset options
|
||||||
|
presetOptions = enum ["obsidian" "lazy" "none"];
|
||||||
|
|
||||||
|
# Log level options
|
||||||
|
logLevelOptions = enum ["error" "warn" "info" "debug" "trace"];
|
||||||
|
|
||||||
|
# Anti-conceal ignore options submodule
|
||||||
|
antiConcealIgnoreOptions = submodule {
|
||||||
|
options = {
|
||||||
|
head_icon = mkOption {
|
||||||
|
type = nullOr (listOf (enum neovimModes));
|
||||||
|
default = null;
|
||||||
|
description = "Modes where head icon anti-conceal behavior will be ignored";
|
||||||
|
};
|
||||||
|
head_background = mkOption {
|
||||||
|
type = nullOr (listOf (enum neovimModes));
|
||||||
|
default = null;
|
||||||
|
description = "Modes where head background anti-conceal behavior will be ignored";
|
||||||
|
};
|
||||||
|
head_border = mkOption {
|
||||||
|
type = nullOr (listOf (enum neovimModes));
|
||||||
|
default = null;
|
||||||
|
description = "Modes where head border anti-conceal behavior will be ignored";
|
||||||
|
};
|
||||||
|
code_language = mkOption {
|
||||||
|
type = nullOr (listOf (enum neovimModes));
|
||||||
|
default = null;
|
||||||
|
description = "Modes where code language anti-conceal behavior will be ignored";
|
||||||
|
};
|
||||||
|
code_background = mkOption {
|
||||||
|
type = nullOr bool;
|
||||||
|
default = true;
|
||||||
|
description = "Whether to ignore code background anti-conceal behavior";
|
||||||
|
};
|
||||||
|
code_border = mkOption {
|
||||||
|
type = nullOr (listOf (enum neovimModes));
|
||||||
|
default = null;
|
||||||
|
description = "Modes where code border anti-conceal behavior will be ignored";
|
||||||
|
};
|
||||||
|
dash = mkOption {
|
||||||
|
type = nullOr (listOf (enum neovimModes));
|
||||||
|
default = null;
|
||||||
|
description = "Modes where dash anti-conceal behavior will be ignored";
|
||||||
|
};
|
||||||
|
bullet = mkOption {
|
||||||
|
type = nullOr (listOf (enum neovimModes));
|
||||||
|
default = null;
|
||||||
|
description = "Modes where bullet anti-conceal behavior will be ignored";
|
||||||
|
};
|
||||||
|
check_icon = mkOption {
|
||||||
|
type = nullOr (listOf (enum neovimModes));
|
||||||
|
default = null;
|
||||||
|
description = "Modes where check icon anti-conceal behavior will be ignored";
|
||||||
|
};
|
||||||
|
check_scope = mkOption {
|
||||||
|
type = nullOr (listOf (enum neovimModes));
|
||||||
|
default = null;
|
||||||
|
description = "Modes where check scope anti-conceal behavior will be ignored";
|
||||||
|
};
|
||||||
|
quote = mkOption {
|
||||||
|
type = nullOr (listOf (enum neovimModes));
|
||||||
|
default = null;
|
||||||
|
description = "Modes where quote anti-conceal behavior will be ignored";
|
||||||
|
};
|
||||||
|
table_border = mkOption {
|
||||||
|
type = nullOr (listOf (enum neovimModes));
|
||||||
|
default = null;
|
||||||
|
description = "Modes where table border anti-conceal behavior will be ignored";
|
||||||
|
};
|
||||||
|
callout = mkOption {
|
||||||
|
type = nullOr (listOf (enum neovimModes));
|
||||||
|
default = null;
|
||||||
|
description = "Modes where callout anti-conceal behavior will be ignored";
|
||||||
|
};
|
||||||
|
link = mkOption {
|
||||||
|
type = nullOr (listOf (enum neovimModes));
|
||||||
|
default = null;
|
||||||
|
description = "Modes where link anti-conceal behavior will be ignored";
|
||||||
|
};
|
||||||
|
sign = mkOption {
|
||||||
|
type = nullOr bool;
|
||||||
|
default = true;
|
||||||
|
description = "Whether to ignore sign anti-conceal behavior";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# Injection options submodule
|
||||||
|
injectionOptions = submodule {
|
||||||
|
options = {
|
||||||
|
enabled = mkOption {
|
||||||
|
type = nullOr bool;
|
||||||
|
default = null;
|
||||||
|
description = "Whether this injection is enabled";
|
||||||
|
};
|
||||||
|
query = mkOption {
|
||||||
|
type = luaInline;
|
||||||
|
description = "Treesitter query for the injection";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
headingWidthType = enum ["block" "full"];
|
||||||
|
|
||||||
|
headingPositionType = enum ["right" "inline" "overlay"];
|
||||||
|
in {
|
||||||
|
options.vim.notes.render-markdown-nvim = {
|
||||||
|
enable = mkEnableOption "Inline markdown rendering";
|
||||||
|
setupOpts = mkPluginSetupOption "render-markdown" {
|
||||||
|
enabled = mkOption {
|
||||||
|
type = bool;
|
||||||
|
default = true;
|
||||||
|
description = "Whether Markdown should be rendered by default";
|
||||||
|
};
|
||||||
|
|
||||||
|
render_modes = mkOption {
|
||||||
|
type = listOf (enum neovimModes);
|
||||||
|
default = ["n" "c" "t"];
|
||||||
|
description = ''
|
||||||
|
Vim modes that will show a rendered view of the markdown file.
|
||||||
|
Individual components can be enabled for other modes.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
max_file_size = mkOption {
|
||||||
|
type = float;
|
||||||
|
default = 10.0;
|
||||||
|
description = "Maximum file size (in MB) that this plugin will attempt to render";
|
||||||
|
};
|
||||||
|
|
||||||
|
debounce = mkOption {
|
||||||
|
type = int;
|
||||||
|
default = 100;
|
||||||
|
description = "Milliseconds that must pass before updating marks";
|
||||||
|
};
|
||||||
|
|
||||||
|
preset = mkOption {
|
||||||
|
type = presetOptions;
|
||||||
|
default = "none";
|
||||||
|
description = "Pre-configured settings to mimic various target user experiences";
|
||||||
|
};
|
||||||
|
|
||||||
|
log_level = mkOption {
|
||||||
|
type = logLevelOptions;
|
||||||
|
default = "error";
|
||||||
|
description = "The level of logs to write to file";
|
||||||
|
};
|
||||||
|
|
||||||
|
log_runtime = mkOption {
|
||||||
|
type = bool;
|
||||||
|
default = false;
|
||||||
|
description = "Print runtime of main update method";
|
||||||
|
};
|
||||||
|
|
||||||
|
file_types = mkOption {
|
||||||
|
type = listOf str;
|
||||||
|
default = ["markdown"];
|
||||||
|
description = "Filetypes this plugin will run on";
|
||||||
|
};
|
||||||
|
|
||||||
|
injections = mkOption {
|
||||||
|
type = attrsOf injectionOptions;
|
||||||
|
default = {
|
||||||
|
gitcommit = {
|
||||||
|
enabled = true;
|
||||||
|
query = ''
|
||||||
|
((message) @injection.content
|
||||||
|
(#set! injection.combined)
|
||||||
|
(#set! injection.include-children)
|
||||||
|
(#set! injection.language "markdown"))
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
description = "Language injections for known filetypes";
|
||||||
|
};
|
||||||
|
|
||||||
|
anti_conceal = {
|
||||||
|
enabled = mkOption {
|
||||||
|
type = bool;
|
||||||
|
default = true;
|
||||||
|
description = "Enable hiding added text on the cursor line";
|
||||||
|
};
|
||||||
|
|
||||||
|
ignore = mkOption {
|
||||||
|
type = antiConcealIgnoreOptions;
|
||||||
|
default = {
|
||||||
|
code_background = true;
|
||||||
|
sign = true;
|
||||||
|
};
|
||||||
|
description = "Elements to always show, ignoring anti-conceal behavior";
|
||||||
|
};
|
||||||
|
|
||||||
|
above = mkOption {
|
||||||
|
type = int;
|
||||||
|
default = 0;
|
||||||
|
description = "Number of lines above cursor to show";
|
||||||
|
};
|
||||||
|
|
||||||
|
below = mkOption {
|
||||||
|
type = int;
|
||||||
|
default = 0;
|
||||||
|
description = "Number of lines below cursor to show";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
padding = {
|
||||||
|
highlight = mkOption {
|
||||||
|
type = str;
|
||||||
|
default = "Normal";
|
||||||
|
description = "Highlight to use when adding whitespace";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
on = {
|
||||||
|
attach = mkOption {
|
||||||
|
type = nullOr luaInline;
|
||||||
|
default = null;
|
||||||
|
description = "Called when plugin initially attaches to a buffer";
|
||||||
|
};
|
||||||
|
|
||||||
|
render = mkOption {
|
||||||
|
type = nullOr luaInline;
|
||||||
|
default = null;
|
||||||
|
description = "Called after plugin renders a buffer";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
latex = {
|
||||||
|
enabled = mkOption {
|
||||||
|
type = nullOr bool;
|
||||||
|
default = null;
|
||||||
|
description = "Whether LaTeX should be rendered";
|
||||||
|
};
|
||||||
|
|
||||||
|
render_modes = mkOption {
|
||||||
|
type = nullOr bool;
|
||||||
|
default = null;
|
||||||
|
description = "Additional modes to render LaTeX";
|
||||||
|
};
|
||||||
|
|
||||||
|
converter = mkOption {
|
||||||
|
type = nullOr str;
|
||||||
|
default = null;
|
||||||
|
description = "Executable used to convert latex formula to rendered unicode";
|
||||||
|
};
|
||||||
|
|
||||||
|
highlight = mkOption {
|
||||||
|
type = nullOr str;
|
||||||
|
default = null;
|
||||||
|
description = "Highlight for LaTeX blocks";
|
||||||
|
};
|
||||||
|
|
||||||
|
top_pad = mkOption {
|
||||||
|
type = nullOr int;
|
||||||
|
default = null;
|
||||||
|
description = "Amount of empty lines above LaTeX blocks";
|
||||||
|
};
|
||||||
|
|
||||||
|
bottom_pad = mkOption {
|
||||||
|
type = nullOr int;
|
||||||
|
default = null;
|
||||||
|
description = "Amount of empty lines below LaTeX blocks";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
heading = {
|
||||||
|
enabled = mkOption {
|
||||||
|
type = nullOr bool;
|
||||||
|
default = null;
|
||||||
|
description = "Enable heading icon & background rendering";
|
||||||
|
};
|
||||||
|
|
||||||
|
render_modes = mkOption {
|
||||||
|
type = nullOr bool;
|
||||||
|
default = null;
|
||||||
|
description = "Additional modes to render headings";
|
||||||
|
};
|
||||||
|
|
||||||
|
sign = mkOption {
|
||||||
|
type = nullOr bool;
|
||||||
|
default = null;
|
||||||
|
description = "Turn on/off sign column related rendering";
|
||||||
|
};
|
||||||
|
|
||||||
|
icons = mkOption {
|
||||||
|
type = nullOr (listOf str);
|
||||||
|
default = null;
|
||||||
|
description = "Icons for different heading levels";
|
||||||
|
};
|
||||||
|
|
||||||
|
position = mkOption {
|
||||||
|
type = nullOr headingPositionType;
|
||||||
|
default = null;
|
||||||
|
description = "How icons fill available space";
|
||||||
|
};
|
||||||
|
|
||||||
|
signs = mkOption {
|
||||||
|
type = nullOr (listOf str);
|
||||||
|
default = null;
|
||||||
|
description = "Signs added to the sign column if enabled";
|
||||||
|
};
|
||||||
|
|
||||||
|
width = mkOption {
|
||||||
|
type = nullOr (either headingWidthType (listOf headingWidthType));
|
||||||
|
default = null;
|
||||||
|
description = "Width of the heading background";
|
||||||
|
};
|
||||||
|
|
||||||
|
left_margin = mkOption {
|
||||||
|
type = nullOr (either float (listOf float));
|
||||||
|
default = null;
|
||||||
|
description = "Margin to add to left of headings";
|
||||||
|
};
|
||||||
|
|
||||||
|
left_pad = mkOption {
|
||||||
|
type = nullOr (either float (listOf float));
|
||||||
|
default = null;
|
||||||
|
description = "Padding to add to left of headings";
|
||||||
|
};
|
||||||
|
|
||||||
|
right_pad = mkOption {
|
||||||
|
type = nullOr (either float (listOf float));
|
||||||
|
default = null;
|
||||||
|
description = "Padding to add to right of headings when width is 'block'";
|
||||||
|
};
|
||||||
|
|
||||||
|
min_width = mkOption {
|
||||||
|
type = nullOr (either int (listOf int));
|
||||||
|
default = null;
|
||||||
|
description = "Minimum width for headings when width is 'block'";
|
||||||
|
};
|
||||||
|
|
||||||
|
border = mkOption {
|
||||||
|
type = nullOr (either bool (listOf bool));
|
||||||
|
default = null;
|
||||||
|
description = "Add border above and below headings";
|
||||||
|
};
|
||||||
|
|
||||||
|
border_virtual = mkOption {
|
||||||
|
type = nullOr bool;
|
||||||
|
default = null;
|
||||||
|
description = "Always use virtual lines for heading borders";
|
||||||
|
};
|
||||||
|
|
||||||
|
border_prefix = mkOption {
|
||||||
|
type = nullOr bool;
|
||||||
|
default = null;
|
||||||
|
description = "Highlight border start using foreground highlight";
|
||||||
|
};
|
||||||
|
|
||||||
|
above = mkOption {
|
||||||
|
type = nullOr str;
|
||||||
|
default = null;
|
||||||
|
description = "Character used above heading for border";
|
||||||
|
};
|
||||||
|
|
||||||
|
below = mkOption {
|
||||||
|
type = nullOr str;
|
||||||
|
default = null;
|
||||||
|
description = "Character used below heading for border";
|
||||||
|
};
|
||||||
|
|
||||||
|
backgrounds = mkOption {
|
||||||
|
type = nullOr (listOf str);
|
||||||
|
default = null;
|
||||||
|
description = "Highlights for heading backgrounds per level";
|
||||||
|
};
|
||||||
|
|
||||||
|
foregrounds = mkOption {
|
||||||
|
type = nullOr (listOf str);
|
||||||
|
default = null;
|
||||||
|
description = "Highlights for heading and sign icons per level";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue