add base setup with dotter

This commit is contained in:
Alexander Navarro 2024-11-08 22:53:56 +00:00 committed by aleidk
parent 6b0da868bb
commit 42e6595b60
177 changed files with 1062 additions and 70 deletions

View file

@ -0,0 +1,32 @@
import = ["/home/aleidk/.config/alacritty/themes/catppuccin/catppuccin-macchiato.toml"]
[env]
TERM = "xterm-256color"
[font]
size = 12.0
[font.bold]
style = "Bold"
[font.bold_italic]
style = "Bold Italic"
[font.italic]
style = "italic"
[font.normal]
family = "JetBrainsMono Nerd Font"
style = "Regular"
[mouse]
hide_when_typing = false
[window]
decorations = "full"
dynamic_padding = true
opacity = 1
[window.padding]
x = 10
y = 10

View file

@ -0,0 +1,844 @@
# Configuration for Alacritty, the GPU enhanced terminal emulator.
# Import additional configuration files
#
# Imports are loaded in order, skipping all missing files, with the importing
# file being loaded last. If a field is already present in a previous import, it
# will be replaced.
#
# All imports must either be absolute paths starting with `/`, or paths relative
# to the user's home directory starting with `~/`.
import:
# - /path/to/alacritty.yml
- ~/.config/alacritty/themes/catppuccin/catppuccin-macchiato.yml
# Any items in the `env` entry below will be added as
# environment variables. Some entries may override variables
# set by alacritty itself.
env:
TERM: xterm-256color
#
# This value is used to set the `$TERM` environment variable for
# each instance of Alacritty. If it is not present, alacritty will
# check the local terminfo database and use `alacritty` if it is
# available, otherwise `xterm-256color` is used.
#TERM: alacritty
window:
# Window dimensions (changes require restart)
#
# Number of lines/columns (not pixels) in the terminal. The number of columns
# must be at least `2`, while using a value of `0` for columns and lines will
# fall back to the window manager's recommended size.
#dimensions:
# columns: 0
# lines: 0
# Window position (changes require restart)
#
# Specified in number of pixels.
# If the position is not set, the window manager will handle the placement.
#position:
# x: 0
# y: 0
# Window padding (changes require restart)
#
# Blank space added around the window in pixels. This padding is scaled
# by DPI and the specified value is always added at both opposing sides.
padding:
x: 10
y: 10
# Spread additional padding evenly around the terminal content.
dynamic_padding: true
# Window decorations
#
# Values for `decorations`:
# - full: Borders and title bar
# - none: Neither borders nor title bar
#
# Values for `decorations` (macOS only):
# - transparent: Title bar, transparent background and title bar buttons
# - buttonless: Title bar, transparent background and no title bar buttons
decorations: full
# Background opacity
#
# Window opacity as a floating point number from `0.0` to `1.0`.
# The value `0.0` is completely transparent and `1.0` is opaque.
opacity: 1
# Startup Mode (changes require restart)
#
# Values for `startup_mode`:
# - Windowed
# - Maximized
# - Fullscreen
#
# Values for `startup_mode` (macOS only):
# - SimpleFullscreen
#startup_mode: Windowed
# Window title
#title: Alacritty
# Allow terminal applications to change Alacritty's window title.
#dynamic_title: true
# Window class (Linux/BSD only):
#class:
# Application instance name
#instance: Alacritty
# General application class
#general: Alacritty
# GTK theme variant (Linux/BSD only)
#
# Override the variant of the GTK theme. Commonly supported values are `dark`
# and `light`. Set this to `None` to use the default theme variant.
#gtk_theme_variant: None
#scrolling:
# Maximum number of lines in the scrollback buffer.
# Specifying '0' will disable scrolling.
#history: 10000
# Scrolling distance multiplier.
#multiplier: 3
# Font configuration
font:
normal:
family: JetBrainsMono Nerd Font
style: Regular
bold:
# family: JetBrainsMono NF
style: Bold
italic:
# family: JetBrainsMono NF
style: italic
bold_italic:
# family: monospace
style: Bold Italic
# Point size
size: 12.0
# Offset is the extra space around each character. `offset.y` can be thought
# of as modifying the line spacing, and `offset.x` as modifying the letter
# spacing.
#offset:
# x: 0
# y: 0
# Glyph offset determines the locations of the glyphs within their cells with
# the default being at the bottom. Increasing `x` moves the glyph to the
# right, increasing `y` moves the glyph upward.
#glyph_offset:
# x: 0
# y: 0
# Thin stroke font rendering (macOS only)
#
# Thin strokes are suitable for retina displays, but for non-retina screens
# it is recommended to set `use_thin_strokes` to `false`.
#use_thin_strokes: true
# Use built-in font for box drawing characters.
#
# If `true`, Alacritty will use a custom built-in font for box drawing
# characters (Unicode points 2500 - 259f).
#
#builtin_box_drawing: true
# If `true`, bold text is drawn using the bright color variants.
#draw_bold_text_with_bright_colors: false
# Colors (Tomorrow Night)
#colors:
# Default colors
#primary:
# background: '#1d1f21'
# foreground: '#c5c8c6'
# Bright and dim foreground colors
#
# The dimmed foreground color is calculated automatically if it is not
# present. If the bright foreground color is not set, or
# `draw_bold_text_with_bright_colors` is `false`, the normal foreground
# color will be used.
#dim_foreground: '#828482'
#bright_foreground: '#eaeaea'
# Cursor colors
#
# Colors which should be used to draw the terminal cursor.
#
# Allowed values are CellForeground/CellBackground, which reference the
# affected cell, or hexadecimal colors like #ff00ff.
#cursor:
# text: CellBackground
# cursor: CellForeground
# Vi mode cursor colors
#
# Colors for the cursor when the vi mode is active.
#
# Allowed values are CellForeground/CellBackground, which reference the
# affected cell, or hexadecimal colors like #ff00ff.
#vi_mode_cursor:
# text: CellBackground
# cursor: CellForeground
# Search colors
#
# Colors used for the search bar and match highlighting.
#search:
# Allowed values are CellForeground/CellBackground, which reference the
# affected cell, or hexadecimal colors like #ff00ff.
#matches:
# foreground: '#000000'
# background: '#ffffff'
#focused_match:
# foreground: '#ffffff'
# background: '#000000'
#bar:
# background: '#c5c8c6'
# foreground: '#1d1f21'
# Keyboard regex hints
#hints:
# First character in the hint label
#
# Allowed values are CellForeground/CellBackground, which reference the
# affected cell, or hexadecimal colors like #ff00ff.
#start:
# foreground: '#1d1f21'
# background: '#e9ff5e'
# All characters after the first one in the hint label
#
# Allowed values are CellForeground/CellBackground, which reference the
# affected cell, or hexadecimal colors like #ff00ff.
#end:
# foreground: '#e9ff5e'
# background: '#1d1f21'
# Line indicator
#
# Color used for the indicator displaying the position in history during
# search and vi mode.
#
# By default, these will use the opposing primary color.
#line_indicator:
# foreground: None
# background: None
# Selection colors
#
# Colors which should be used to draw the selection area.
#
# Allowed values are CellForeground/CellBackground, which reference the
# affected cell, or hexadecimal colors like #ff00ff.
#selection:
# text: CellBackground
# background: CellForeground
# Normal colors
#normal:
# black: '#1d1f21'
# red: '#cc6666'
# green: '#b5bd68'
# yellow: '#f0c674'
# blue: '#81a2be'
# magenta: '#b294bb'
# cyan: '#8abeb7'
# white: '#c5c8c6'
# Bright colors
#bright:
# black: '#666666'
# red: '#d54e53'
# green: '#b9ca4a'
# yellow: '#e7c547'
# blue: '#7aa6da'
# magenta: '#c397d8'
# cyan: '#70c0b1'
# white: '#eaeaea'
# Dim colors
#
# If the dim colors are not set, they will be calculated automatically based
# on the `normal` colors.
#dim:
# black: '#131415'
# red: '#864343'
# green: '#777c44'
# yellow: '#9e824c'
# blue: '#556a7d'
# magenta: '#75617b'
# cyan: '#5b7d78'
# white: '#828482'
# Indexed Colors
#
# The indexed colors include all colors from 16 to 256.
# When these are not set, they're filled with sensible defaults.
#
# Example:
# `- { index: 16, color: '#ff00ff' }`
#
#indexed_colors: []
# Transparent cell backgrounds
#
# Whether or not `window.opacity` applies to all cell backgrounds or only to
# the default background. When set to `true` all cells will be transparent
# regardless of their background color.
#transparent_background_colors: false
# Bell
#
# The bell is rung every time the BEL control character is received.
#bell:
# Visual Bell Animation
#
# Animation effect for flashing the screen when the visual bell is rung.
#
# Values for `animation`:
# - Ease
# - EaseOut
# - EaseOutSine
# - EaseOutQuad
# - EaseOutCubic
# - EaseOutQuart
# - EaseOutQuint
# - EaseOutExpo
# - EaseOutCirc
# - Linear
#animation: EaseOutExpo
# Duration of the visual bell flash in milliseconds. A `duration` of `0` will
# disable the visual bell animation.
#duration: 0
# Visual bell animation color.
#color: '#ffffff'
# Bell Command
#
# This program is executed whenever the bell is rung.
#
# When set to `command: None`, no command will be executed.
#
# Example:
# command:
# program: notify-send
# args: ["Hello, World!"]
#
#command: None
#selection:
# This string contains all characters that are used as separators for
# "semantic words" in Alacritty.
#semantic_escape_chars: ",│`|:\"' ()[]{}<>\t"
# When set to `true`, selected text will be copied to the primary clipboard.
#save_to_clipboard: false
#cursor:
# Cursor style
#style:
# Cursor shape
#
# Values for `shape`:
# - ▇ Block
# - _ Underline
# - | Beam
#shape: Block
# Cursor blinking state
#
# Values for `blinking`:
# - Never: Prevent the cursor from ever blinking
# - Off: Disable blinking by default
# - On: Enable blinking by default
# - Always: Force the cursor to always blink
#blinking: Off
# Vi mode cursor style
#
# If the vi mode cursor style is `None` or not specified, it will fall back to
# the style of the active value of the normal cursor.
#
# See `cursor.style` for available options.
#vi_mode_style: None
# Cursor blinking interval in milliseconds.
#blink_interval: 750
# If this is `true`, the cursor will be rendered as a hollow box when the
# window is not focused.
#unfocused_hollow: true
# Thickness of the cursor relative to the cell width as floating point number
# from `0.0` to `1.0`.
#thickness: 0.15
# Live config reload (changes require restart)
#live_config_reload: true
# Shell
#
# You can set `shell.program` to the path of your favorite shell, e.g.
# `/bin/fish`. Entries in `shell.args` are passed unmodified as arguments to the
# shell.
#
# Default:
# - (macOS) /bin/bash --login
# - (Linux/BSD) user login shell
# - (Windows) powershell
# shell:
# program: /bin/zsh
# args:
# - -l
# - -c
# # Open tmux session selector on startup
# - "source ~/.config/zsh/functions/tmux.zsh && tm || echo 'Error running tmux...'"
# Startup directory
#
# Directory the shell is started in. If this is unset, or `None`, the working
# directory of the parent process will be used.
#working_directory: None
# Send ESC (\x1b) before characters when alt is pressed.
#alt_send_esc: true
# Offer IPC using `alacritty msg` (unix only)
#ipc_socket: true
mouse:
# Click settings
#
# The `double_click` and `triple_click` settings control the time
# alacritty should wait for accepting multiple clicks as one double
# or triple click.
#double_click: { threshold: 300 }
#triple_click: { threshold: 300 }
# If this is `true`, the cursor is temporarily hidden when typing.
hide_when_typing: false
# Regex hints
#
# Terminal hints can be used to find text in the visible part of the terminal
# and pipe it to other applications.
#hints:
# Keys used for the hint labels.
#alphabet: "jfkdls;ahgurieowpq"
# List with all available hints
#
# Each hint must have a `regex` and either an `action` or a `command` field.
# The fields `mouse`, `binding` and `post_processing` are optional.
#
# The fields `command`, `binding.key`, `binding.mods`, `binding.mode` and
# `mouse.mods` accept the same values as they do in the `key_bindings` section.
#
# The `mouse.enabled` field controls if the hint should be underlined while
# the mouse with all `mouse.mods` keys held or the vi mode cursor is above it.
#
# If the `post_processing` field is set to `true`, heuristics will be used to
# shorten the match if there are characters likely not to be part of the hint
# (e.g. a trailing `.`). This is most useful for URIs.
#
# Values for `action`:
# - Copy
# Copy the hint's text to the clipboard.
# - Paste
# Paste the hint's text to the terminal or search.
# - Select
# Select the hint's text.
# - MoveViModeCursor
# Move the vi mode cursor to the beginning of the hint.
#enabled:
# - regex: "(ipfs:|ipns:|magnet:|mailto:|gemini:|gopher:|https:|http:|news:|file:|git:|ssh:|ftp:)\
# [^\u0000-\u001F\u007F-\u009F<>\"\\s{-}\\^⟨⟩`]+"
# command: xdg-open
# post_processing: true
# mouse:
# enabled: true
# mods: None
# binding:
# key: U
# mods: Control|Shift
# Mouse bindings
#
# Mouse bindings are specified as a list of objects, much like the key
# bindings further below.
#
# To trigger mouse bindings when an application running within Alacritty
# captures the mouse, the `Shift` modifier is automatically added as a
# requirement.
#
# Each mouse binding will specify a:
#
# - `mouse`:
#
# - Middle
# - Left
# - Right
# - Numeric identifier such as `5`
#
# - `action` (see key bindings for actions not exclusive to mouse mode)
#
# - Mouse exclusive actions:
#
# - ExpandSelection
# Expand the selection to the current mouse cursor location.
#
# And optionally:
#
# - `mods` (see key bindings)
#mouse_bindings:
# - { mouse: Right, action: ExpandSelection }
# - { mouse: Right, mods: Control, action: ExpandSelection }
# - { mouse: Middle, mode: ~Vi, action: PasteSelection }
# Key bindings
#
# Key bindings are specified as a list of objects. For example, this is the
# default paste binding:
#
# `- { key: V, mods: Control|Shift, action: Paste }`
#
# Each key binding will specify a:
#
# - `key`: Identifier of the key pressed
#
# - A-Z
# - F1-F24
# - Key0-Key9
#
# A full list with available key codes can be found here:
# https://docs.rs/glutin/*/glutin/event/enum.VirtualKeyCode.html#variants
#
# Instead of using the name of the keys, the `key` field also supports using
# the scancode of the desired key. Scancodes have to be specified as a
# decimal number. This command will allow you to display the hex scancodes
# for certain keys:
#
# `showkey --scancodes`.
#
# Then exactly one of:
#
# - `chars`: Send a byte sequence to the running application
#
# The `chars` field writes the specified string to the terminal. This makes
# it possible to pass escape sequences. To find escape codes for bindings
# like `PageUp` (`"\x1b[5~"`), you can run the command `showkey -a` outside
# of tmux. Note that applications use terminfo to map escape sequences back
# to keys. It is therefore required to update the terminfo when changing an
# escape sequence.
#
# - `action`: Execute a predefined action
#
# - ToggleViMode
# - SearchForward
# Start searching toward the right of the search origin.
# - SearchBackward
# Start searching toward the left of the search origin.
# - Copy
# - Paste
# - IncreaseFontSize
# - DecreaseFontSize
# - ResetFontSize
# - ScrollPageUp
# - ScrollPageDown
# - ScrollHalfPageUp
# - ScrollHalfPageDown
# - ScrollLineUp
# - ScrollLineDown
# - ScrollToTop
# - ScrollToBottom
# - ClearHistory
# Remove the terminal's scrollback history.
# - Hide
# Hide the Alacritty window.
# - Minimize
# Minimize the Alacritty window.
# - Quit
# Quit Alacritty.
# - ToggleFullscreen
# - SpawnNewInstance
# Spawn a new instance of Alacritty.
# - CreateNewWindow
# Create a new Alacritty window from the current process.
# - ClearLogNotice
# Clear Alacritty's UI warning and error notice.
# - ClearSelection
# Remove the active selection.
# - ReceiveChar
# - None
#
# - Vi mode exclusive actions:
#
# - Open
# Perform the action of the first matching hint under the vi mode cursor
# with `mouse.enabled` set to `true`.
# - ToggleNormalSelection
# - ToggleLineSelection
# - ToggleBlockSelection
# - ToggleSemanticSelection
# Toggle semantic selection based on `selection.semantic_escape_chars`.
#
# - Vi mode exclusive cursor motion actions:
#
# - Up
# One line up.
# - Down
# One line down.
# - Left
# One character left.
# - Right
# One character right.
# - First
# First column, or beginning of the line when already at the first column.
# - Last
# Last column, or beginning of the line when already at the last column.
# - FirstOccupied
# First non-empty cell in this terminal row, or first non-empty cell of
# the line when already at the first cell of the row.
# - High
# Top of the screen.
# - Middle
# Center of the screen.
# - Low
# Bottom of the screen.
# - SemanticLeft
# Start of the previous semantically separated word.
# - SemanticRight
# Start of the next semantically separated word.
# - SemanticLeftEnd
# End of the previous semantically separated word.
# - SemanticRightEnd
# End of the next semantically separated word.
# - WordLeft
# Start of the previous whitespace separated word.
# - WordRight
# Start of the next whitespace separated word.
# - WordLeftEnd
# End of the previous whitespace separated word.
# - WordRightEnd
# End of the next whitespace separated word.
# - Bracket
# Character matching the bracket at the cursor's location.
# - SearchNext
# Beginning of the next match.
# - SearchPrevious
# Beginning of the previous match.
# - SearchStart
# Start of the match to the left of the vi mode cursor.
# - SearchEnd
# End of the match to the right of the vi mode cursor.
#
# - Search mode exclusive actions:
# - SearchFocusNext
# Move the focus to the next search match.
# - SearchFocusPrevious
# Move the focus to the previous search match.
# - SearchConfirm
# - SearchCancel
# - SearchClear
# Reset the search regex.
# - SearchDeleteWord
# Delete the last word in the search regex.
# - SearchHistoryPrevious
# Go to the previous regex in the search history.
# - SearchHistoryNext
# Go to the next regex in the search history.
#
# - macOS exclusive actions:
# - ToggleSimpleFullscreen
# Enter fullscreen without occupying another space.
#
# - Linux/BSD exclusive actions:
#
# - CopySelection
# Copy from the selection buffer.
# - PasteSelection
# Paste from the selection buffer.
#
# - `command`: Fork and execute a specified command plus arguments
#
# The `command` field must be a map containing a `program` string and an
# `args` array of command line parameter strings. For example:
# `{ program: "alacritty", args: ["-e", "vttest"] }`
#
# And optionally:
#
# - `mods`: Key modifiers to filter binding actions
#
# - Command
# - Control
# - Option
# - Super
# - Shift
# - Alt
#
# Multiple `mods` can be combined using `|` like this:
# `mods: Control|Shift`.
# Whitespace and capitalization are relevant and must match the example.
#
# - `mode`: Indicate a binding for only specific terminal reported modes
#
# This is mainly used to send applications the correct escape sequences
# when in different modes.
#
# - AppCursor
# - AppKeypad
# - Search
# - Alt
# - Vi
#
# A `~` operator can be used before a mode to apply the binding whenever
# the mode is *not* active, e.g. `~Alt`.
#
# Bindings are always filled by default, but will be replaced when a new
# binding with the same triggers is defined. To unset a default binding, it can
# be mapped to the `ReceiveChar` action. Alternatively, you can use `None` for
# a no-op if you do not wish to receive input characters for that binding.
#
# If the same trigger is assigned to multiple actions, all of them are executed
# in the order they were defined in.
#key_bindings:
#- { key: Paste, action: Paste }
#- { key: Copy, action: Copy }
#- { key: L, mods: Control, action: ClearLogNotice }
#- { key: L, mods: Control, mode: ~Vi|~Search, chars: "\x0c" }
#- { key: PageUp, mods: Shift, mode: ~Alt, action: ScrollPageUp, }
#- { key: PageDown, mods: Shift, mode: ~Alt, action: ScrollPageDown }
#- { key: Home, mods: Shift, mode: ~Alt, action: ScrollToTop, }
#- { key: End, mods: Shift, mode: ~Alt, action: ScrollToBottom }
# Vi Mode
#- { key: Space, mods: Shift|Control, mode: ~Search, action: ToggleViMode }
#- { key: Space, mods: Shift|Control, mode: Vi|~Search, action: ScrollToBottom }
#- { key: Escape, mode: Vi|~Search, action: ClearSelection }
#- { key: I, mode: Vi|~Search, action: ToggleViMode }
#- { key: I, mode: Vi|~Search, action: ScrollToBottom }
#- { key: C, mods: Control, mode: Vi|~Search, action: ToggleViMode }
#- { key: Y, mods: Control, mode: Vi|~Search, action: ScrollLineUp }
#- { key: E, mods: Control, mode: Vi|~Search, action: ScrollLineDown }
#- { key: G, mode: Vi|~Search, action: ScrollToTop }
#- { key: G, mods: Shift, mode: Vi|~Search, action: ScrollToBottom }
#- { key: B, mods: Control, mode: Vi|~Search, action: ScrollPageUp }
#- { key: F, mods: Control, mode: Vi|~Search, action: ScrollPageDown }
#- { key: U, mods: Control, mode: Vi|~Search, action: ScrollHalfPageUp }
#- { key: D, mods: Control, mode: Vi|~Search, action: ScrollHalfPageDown }
#- { key: Y, mode: Vi|~Search, action: Copy }
#- { key: Y, mode: Vi|~Search, action: ClearSelection }
#- { key: Copy, mode: Vi|~Search, action: ClearSelection }
#- { key: V, mode: Vi|~Search, action: ToggleNormalSelection }
#- { key: V, mods: Shift, mode: Vi|~Search, action: ToggleLineSelection }
#- { key: V, mods: Control, mode: Vi|~Search, action: ToggleBlockSelection }
#- { key: V, mods: Alt, mode: Vi|~Search, action: ToggleSemanticSelection }
#- { key: Return, mode: Vi|~Search, action: Open }
#- { key: K, mode: Vi|~Search, action: Up }
#- { key: J, mode: Vi|~Search, action: Down }
#- { key: H, mode: Vi|~Search, action: Left }
#- { key: L, mode: Vi|~Search, action: Right }
#- { key: Up, mode: Vi|~Search, action: Up }
#- { key: Down, mode: Vi|~Search, action: Down }
#- { key: Left, mode: Vi|~Search, action: Left }
#- { key: Right, mode: Vi|~Search, action: Right }
#- { key: Key0, mode: Vi|~Search, action: First }
#- { key: Key4, mods: Shift, mode: Vi|~Search, action: Last }
#- { key: Key6, mods: Shift, mode: Vi|~Search, action: FirstOccupied }
#- { key: H, mods: Shift, mode: Vi|~Search, action: High }
#- { key: M, mods: Shift, mode: Vi|~Search, action: Middle }
#- { key: L, mods: Shift, mode: Vi|~Search, action: Low }
#- { key: B, mode: Vi|~Search, action: SemanticLeft }
#- { key: W, mode: Vi|~Search, action: SemanticRight }
#- { key: E, mode: Vi|~Search, action: SemanticRightEnd }
#- { key: B, mods: Shift, mode: Vi|~Search, action: WordLeft }
#- { key: W, mods: Shift, mode: Vi|~Search, action: WordRight }
#- { key: E, mods: Shift, mode: Vi|~Search, action: WordRightEnd }
#- { key: Key5, mods: Shift, mode: Vi|~Search, action: Bracket }
#- { key: Slash, mode: Vi|~Search, action: SearchForward }
#- { key: Slash, mods: Shift, mode: Vi|~Search, action: SearchBackward }
#- { key: N, mode: Vi|~Search, action: SearchNext }
#- { key: N, mods: Shift, mode: Vi|~Search, action: SearchPrevious }
# Search Mode
#- { key: Return, mode: Search|Vi, action: SearchConfirm }
#- { key: Escape, mode: Search, action: SearchCancel }
#- { key: C, mods: Control, mode: Search, action: SearchCancel }
#- { key: U, mods: Control, mode: Search, action: SearchClear }
#- { key: W, mods: Control, mode: Search, action: SearchDeleteWord }
#- { key: P, mods: Control, mode: Search, action: SearchHistoryPrevious }
#- { key: N, mods: Control, mode: Search, action: SearchHistoryNext }
#- { key: Up, mode: Search, action: SearchHistoryPrevious }
#- { key: Down, mode: Search, action: SearchHistoryNext }
#- { key: Return, mode: Search|~Vi, action: SearchFocusNext }
#- { key: Return, mods: Shift, mode: Search|~Vi, action: SearchFocusPrevious }
# (Windows, Linux, and BSD only)
#- { key: V, mods: Control|Shift, mode: ~Vi, action: Paste }
#- { key: C, mods: Control|Shift, action: Copy }
#- { key: F, mods: Control|Shift, mode: ~Search, action: SearchForward }
#- { key: B, mods: Control|Shift, mode: ~Search, action: SearchBackward }
#- { key: C, mods: Control|Shift, mode: Vi|~Search, action: ClearSelection }
#- { key: Insert, mods: Shift, action: PasteSelection }
#- { key: Key0, mods: Control, action: ResetFontSize }
#- { key: Equals, mods: Control, action: IncreaseFontSize }
#- { key: Plus, mods: Control, action: IncreaseFontSize }
#- { key: NumpadAdd, mods: Control, action: IncreaseFontSize }
#- { key: Minus, mods: Control, action: DecreaseFontSize }
#- { key: NumpadSubtract, mods: Control, action: DecreaseFontSize }
# (Windows only)
#- { key: Return, mods: Alt, action: ToggleFullscreen }
# (macOS only)
#- { key: K, mods: Command, mode: ~Vi|~Search, chars: "\x0c" }
#- { key: K, mods: Command, mode: ~Vi|~Search, action: ClearHistory }
#- { key: Key0, mods: Command, action: ResetFontSize }
#- { key: Equals, mods: Command, action: IncreaseFontSize }
#- { key: Plus, mods: Command, action: IncreaseFontSize }
#- { key: NumpadAdd, mods: Command, action: IncreaseFontSize }
#- { key: Minus, mods: Command, action: DecreaseFontSize }
#- { key: NumpadSubtract, mods: Command, action: DecreaseFontSize }
#- { key: V, mods: Command, action: Paste }
#- { key: C, mods: Command, action: Copy }
#- { key: C, mods: Command, mode: Vi|~Search, action: ClearSelection }
#- { key: H, mods: Command, action: Hide }
#- { key: H, mods: Command|Alt, action: HideOtherApplications }
#- { key: M, mods: Command, action: Minimize }
#- { key: Q, mods: Command, action: Quit }
#- { key: W, mods: Command, action: Quit }
#- { key: N, mods: Command, action: SpawnNewInstance }
#- { key: F, mods: Command|Control, action: ToggleFullscreen }
#- { key: F, mods: Command, mode: ~Search, action: SearchForward }
#- { key: B, mods: Command, mode: ~Search, action: SearchBackward }
#debug:
# Display the time it takes to redraw each frame.
#render_timer: false
# Keep the log file after quitting Alacritty.
#persistent_logging: false
# Log level
#
# Values for `log_level`:
# - Off
# - Error
# - Warn
# - Info
# - Debug
# - Trace
#log_level: Warn
# Print all received window events.
#print_events: false

View file

27
config/bat/config Normal file
View file

@ -0,0 +1,27 @@
# This is `bat`s configuration file. Each line either contains a comment or
# a command-line option that you want to pass to `bat` by default. You can
# run `bat --help` to get a list of all possible configuration options.
# Specify desired highlighting theme (e.g. "TwoDark"). Run `bat --list-themes`
# for a list of all available themes
--theme="Catppuccin-macchiato"
--style="changes,numbers"
# Enable this to use italic text on the terminal. This is not supported on all
# terminal emulators (like tmux, by default):
#--italic-text=always
# Uncomment the following line to disable automatic paging:
#--paging=never
# Uncomment the following line if you are using less version >= 551 and want to
# enable mouse scrolling support in `bat` when running inside tmux. This might
# disable text selection, unless you press shift.
#--pager="less --RAW-CONTROL-CHARS --quit-if-one-screen --mouse"
# Syntax mappings: map a certain filename pattern to a language.
# Example 1: use the C++ syntax for Arduino .ino files
# Example 2: Use ".gitignore"-style highlighting for ".ignore" files
#--map-syntax "*.ino:C++"
#--map-syntax ".ignore:Git Ignore"

197
config/foot/foot.ini Normal file
View file

@ -0,0 +1,197 @@
# -*- conf -*-
# shell=$SHELL (if set, otherwise user's default shell from /etc/passwd)
# term=foot (or xterm-256color if built with -Dterminfo=disabled)
# login-shell=no
include=~/.config/foot/themes/catppuccin/catppuccin-macchiato.conf
# app-id=foot
# title=foot
# locked-title=no
font=JetBrainsMono NF:style=Regular:size=11
font-bold=JetBrainsMono NF:style=Bold:size=11
font-italic=JetBrainsMono NF:style=Italic:size=11
font-bold-italic=JetBrainsMono NF:style=Bold Italic:size=11
# line-height=<font metrics>
# letter-spacing=0
# horizontal-letter-offset=0
# vertical-letter-offset=0
# underline-offset=<font metrics>
# box-drawings-uses-font-glyphs=no
# dpi-aware=auto
# initial-window-size-pixels=700x500 # Or,
# initial-window-size-chars=<COLSxROWS>
# initial-window-mode=windowed
pad=10x10
# resize-delay-ms=100
# notify=notify-send -a ${app-id} -i ${app-id} ${title} ${body}
# bold-text-in-bright=no
# word-delimiters=,│`|:"'()[]{}<>
# selection-target=primary
# workers=<number of logical CPUs>
[environment]
# name=value
[bell]
# urgent=no
# notify=no
# command=
# command-focused=no
[scrollback]
# lines=1000
# multiplier=3.0
# indicator-position=relative
# indicator-format=
[url]
# launch=xdg-open ${url}
# label-letters=sadfjklewcmpgh
# osc8-underline=url-mode
# protocols=http, https, ftp, ftps, file, gemini, gopher
# uri-characters=abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.,~:;/?#@!$&%*+="'()[]
[cursor]
# style=block
# color=<inverse foreground/background>
# blink=no
# beam-thickness=1.5
# underline-thickness=<font underline thickness>
[mouse]
# hide-when-typing=no
# alternate-scroll-mode=yes
[colors]
alpha=0.9
# foreground=dcdccc
# background=111111
## Normal/regular colors (color palette 0-7)
# regular0=222222 # black
# regular1=cc9393 # red
# regular2=7f9f7f # green
# regular3=d0bf8f # yellow
# regular4=6ca0a3 # blue
# regular5=dc8cc3 # magenta
# regular6=93e0e3 # cyan
# regular7=dcdccc # white
## Bright colors (color palette 8-15)
# bright0=666666 # bright black
# bright1=dca3a3 # bright red
# bright2=bfebbf # bright green
# bright3=f0dfaf # bright yellow
# bright4=8cd0d3 # bright blue
# bright5=fcace3 # bright magenta
# bright6=b3ffff # bright cyan
# bright7=ffffff # bright white
## dimmed colors (see foot.ini(5) man page)
# dim0=<not set>
# ...
# dim7=<not-set>
## The remaining 256-color palette
# 16 = <256-color palette #16>
# ...
# 255 = <256-color palette #255>
## Misc colors
# selection-foreground=<inverse foreground/background>
# selection-background=<inverse foreground/background>
# jump-labels=<regular0> <regular3> # black-on-yellow
# scrollback-indicator=<regular0> <bright4> # black-on-bright-blue
# search-box-no-match=<regular0> <regular1> # black-on-red
# search-box-match=<regular0> <regular3> # black-on-yellow
# urls=<regular3>
[csd]
preferred=none
# size=26
# font=<primary font>
# color=<foreground color>
# hide-when-typing=no
# border-width=0
# border-color=<csd.color>
# button-width=26
# button-color=<background color>
# button-minimize-color=<regular4>
# button-maximize-color=<regular2>
# button-close-color=<regular1>
[key-bindings]
# scrollback-up-page=Shift+Page_Up
# scrollback-up-half-page=none
# scrollback-up-line=none
# scrollback-down-page=Shift+Page_Down
# scrollback-down-half-page=none
# scrollback-down-line=none
# clipboard-copy=Control+Shift+c XF86Copy
# clipboard-paste=Control+Shift+v XF86Paste
# primary-paste=Shift+Insert
# search-start=Control+Shift+r
# font-increase=Control+plus Control+equal Control+KP_Add
# font-decrease=Control+minus Control+KP_Subtract
# font-reset=Control+0 Control+KP_0
# spawn-terminal=Control+Shift+n
# minimize=none
# maximize=none
# fullscreen=none
# pipe-visible=[sh -c "xurls | fuzzel | xargs -r firefox"] none
# pipe-scrollback=[sh -c "xurls | fuzzel | xargs -r firefox"] none
# pipe-selected=[xargs -r firefox] none
# show-urls-launch=Control+Shift+u
# show-urls-copy=none
# show-urls-persistent=none
# prompt-prev=Control+Shift+z
# prompt-next=Control+Shift+x
# unicode-input=none
# noop=none
[search-bindings]
# cancel=Control+g Control+c Escape
# commit=Return
# find-prev=Control+r
# find-next=Control+s
# cursor-left=Left Control+b
# cursor-left-word=Control+Left Mod1+b
# cursor-right=Right Control+f
# cursor-right-word=Control+Right Mod1+f
# cursor-home=Home Control+a
# cursor-end=End Control+e
# delete-prev=BackSpace
# delete-prev-word=Mod1+BackSpace Control+BackSpace
# delete-next=Delete
# delete-next-word=Mod1+d Control+Delete
# extend-to-word-boundary=Control+w
# extend-to-next-whitespace=Control+Shift+w
# clipboard-paste=Control+v Control+Shift+v Control+y XF86Paste
# primary-paste=Shift+Insert
# unicode-input=none
[url-bindings]
# cancel=Control+g Control+c Control+d Escape
# toggle-url-visible=t
[text-bindings]
# \x03=Mod4+c # Map Super+c -> Ctrl+c
[mouse-bindings]
# selection-override-modifiers=Shift
# primary-paste=BTN_MIDDLE
# select-begin=BTN_LEFT
# select-begin-block=Control+BTN_LEFT
# select-extend=BTN_RIGHT
# select-extend-character-wise=Control+BTN_RIGHT
# select-word=BTN_LEFT-2
# select-word-whitespace=Control+BTN_LEFT-2
# select-row=BTN_LEFT-3
# vim: ft=dosini

View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021 Catppuccin
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View file

@ -0,0 +1,32 @@
<h3 align="center">
<img src="https://raw.githubusercontent.com/catppuccin/catppuccin/main/assets/logos/exports/1544x1544_circle.png" width="100" alt="Logo"/><br/>
<img src="https://raw.githubusercontent.com/catppuccin/catppuccin/main/assets/misc/transparent.png" height="30" width="0px"/>
Catppuccin for <a href="https://codeberg.org/dnkl/foot">Foot</a>
<img src="https://raw.githubusercontent.com/catppuccin/catppuccin/main/assets/misc/transparent.png" height="30" width="0px"/>
</h3>
<p align="center">
<a href="https://github.com/catppuccin/foot/stargazers"><img src="https://img.shields.io/github/stars/catppuccin/foot?colorA=363a4f&colorB=b7bdf8&style=for-the-badge"></a>
<a href="https://github.com/catppuccin/foot/issues"><img src="https://img.shields.io/github/issues/catppuccin/foot?colorA=363a4f&colorB=f5a97f&style=for-the-badge"></a>
<a href="https://github.com/catppuccin/foot/contributors"><img src="https://img.shields.io/github/contributors/catppuccin/foot?colorA=363a4f&colorB=a6da95&style=for-the-badge"></a>
</p>
<p align="center">
<img src="https://raw.githubusercontent.com/catppuccin/foot-catppuccin/main/assets/foot.png"/>
</p>
## Usage
1. Copy the contents of `catppuccin.conf` colorscheme you want into your Foot config file (usually stored at `~/.config/foot/foot.ini`)
## 💝 Thanks to
- [Pocco81](https://github.com/Pocco81)
- [crdpa](https://github.com/crdpa)
- [Thibault Andreis](https://github.com/ThibaultAndreis)
&nbsp;
<p align="center"><img src="https://raw.githubusercontent.com/catppuccin/catppuccin/main/assets/footers/gray0_ctp_on_line.svg?sanitize=true" /></p>
<p align="center">Copyright &copy; 2021-present <a href="https://github.com/catppuccin" target="_blank">Catppuccin Org</a>
<p align="center"><a href="https://github.com/catppuccin/catppuccin/blob/main/LICENSE"><img src="https://img.shields.io/static/v1.svg?style=for-the-badge&label=License&message=MIT&logoColor=d9e0ee&colorA=363a4f&colorB=b7bdf8"/></a></p>

Binary file not shown.

After

Width:  |  Height:  |  Size: 313 KiB

View file

@ -0,0 +1,19 @@
[colors]
foreground=c6d0f5 # Text
background=303446 # Base
regular0=51576d # Surface 1
regular1=e78284 # red
regular2=a6d189 # green
regular3=e5c890 # yellow
regular4=8caaee # blue
regular5=f4b8e4 # pink
regular6=81c8be # teal
regular7=b5bfe2 # Subtext 1
bright0=626880 # Surface 2
bright1=e78284 # red
bright2=a6d189 # green
bright3=e5c890 # yellow
bright4=8caaee # blue
bright5=f4b8e4 # pink
bright6=81c8be # teal
bright7=a5adce # Subtext 0

View file

@ -0,0 +1,19 @@
[colors]
foreground=4c4f69 # Text
background=eff1f5 # Base
regular0=5c5f77 # Subtext 1
regular1=d20f39 # red
regular2=40a02b # green
regular3=df8e1d # yellow
regular4=1e66f5 # blue
regular5=ea76cb # pink
regular6=179299 # teal
regular7=acb0be # Surface 2
bright0=6c6f85 # Subtext 0
bright1=d20f39 # red
bright2=40a02b # green
bright3=df8e1d # yellow
bright4=1e66f5 # blue
bright5=ea76cb # pink
bright6=179299 # teal
bright7=bcc0cc # Surface 1

View file

@ -0,0 +1,19 @@
[colors]
foreground=cad3f5 # Text
background=24273a # Base
regular0=494d64 # Surface 1
regular1=ed8796 # red
regular2=a6da95 # green
regular3=eed49f # yellow
regular4=8aadf4 # blue
regular5=f5bde6 # pink
regular6=8bd5ca # teal
regular7=b8c0e0 # Subtext 1
bright0=5b6078 # Surface 2
bright1=ed8796 # red
bright2=a6da95 # green
bright3=eed49f # yellow
bright4=8aadf4 # blue
bright5=f5bde6 # pink
bright6=8bd5ca # teal
bright7=a5adcb # Subtext 0

View file

@ -0,0 +1,19 @@
[colors]
foreground=cdd6f4 # Text
background=1e1e2e # Base
regular0=45475a # Surface 1
regular1=f38ba8 # red
regular2=a6e3a1 # green
regular3=f9e2af # yellow
regular4=89b4fa # blue
regular5=f5c2e7 # pink
regular6=94e2d5 # teal
regular7=bac2de # Subtext 1
bright0=585b70 # Surface 2
bright1=f38ba8 # red
bright2=a6e3a1 # green
bright3=f9e2af # yellow
bright4=89b4fa # blue
bright5=f5c2e7 # pink
bright6=94e2d5 # teal
bright7=a6adc8 # Subtext 0

View file

@ -0,0 +1,34 @@
# EditorConfig helps developers define and maintain consistent
# coding styles between different editors and IDEs
# EditorConfig is awesome: https://EditorConfig.org
root = true
[*]
charset = utf-8
indent_size = 2
indent_style = space
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
# go
[*.go]
indent_style = tab
indent_size = 4
# python
[*.{ini,py,py.tpl,rst}]
indent_size = 4
# rust
[*.rs]
indent_size = 4
# documentation, utils
[*.{md,mdx,diff}]
trim_trailing_whitespace = false
# windows shell scripts
[*.{cmd,bat,ps1}]
end_of_line = crlf

View file

@ -0,0 +1 @@
gitdir: ../../../../.git/modules/config/foot/themes/catppuccin

49
config/fzf/forgitrc Normal file
View file

@ -0,0 +1,49 @@
forgit-list-command-widget() {
local cmd=$(alias | grep 'forgit' | sed -E 's/::/ /g; s/=/ :- /g; s/for//g' | \
awk -v BLD=${BLD} -v RST=${RST} -v BLU=${BLU} -v CYN=${CYN} -F":" '{print BLU BLD $1 RST ":" CYN $2 RST }' | \
column -ts":")
LBUFFER="$LBUFFER$( \
fzf-tmux -p -w 30% -h 53% --preview-window=hidden --prompt=' List > ' \
--header=$'Alias\t Description' <<< "$cmd" | awk '{print $1}')"
if [[ -n $LBUFFER ]]; then
zle accept-line
fi
zle reset-prompt
}
zle -N forgit-list-command-widget
bindkey '^[g^[l' forgit-list-command-widget #<Alt-G+Alt-L>
export FORGIT_FZF_SHOW_HELP_OPTS="$(
cat <<-EOF
Forgit Commands (Aliases)
fga add
fgbl blame
fgbd branch delete
fgcb checkout branch
fgco checkout commit
fgcf checkout file
fgct checkout tag
fgcp cherry pick
fgclean clean
fgd diff
fgfu fixup
fgi ignore
fglo log
fgrb rebase
fgrh reset head
fgrev revert commit
fgsta stash push
fgsts stash show
EOF
)"
export FORGIT_FZF_DEFAULT_OPTS="
--cycle
--reverse
--height '80%'
--preview-window=nohidden
--bind 'alt-?:preview(printf \"${FORGIT_FZF_SHOW_HELP_OPTS}\")'
"

128
config/fzf/fzfrc Normal file
View file

@ -0,0 +1,128 @@
export FZF_SHOW_HELP_OPTS="$(
cat <<-EOF
FZF Keybinds Shortcut
? Toggle/Hide Preview
C-space Change preview layout
C-e Open in Editor
C-v Open in VsCode
C-o Launch Application Chooser
M-o Open in Default Appllication
C-/ Directory: Navigate on broot
C-/ File: Open in Pager (bat)
M-s Toggle Sort
C-y Copy/Yank
C-M-y Copy/Yank Working Directory
C-a Select all
C-M-d Deselect All
Del Delete/Remove file
Alt-? Help (this page)
ESC Quit
EOF
)"
export FZF_DEFAULT_OPTS=" \
--color=bg+:#363a4f,bg:#24273a,spinner:#f4dbd6,hl:#ed8796 \
--color=fg:#cad3f5,header:#ed8796,info:#c6a0f6,pointer:#f4dbd6 \
--color=marker:#f4dbd6,fg+:#cad3f5,prompt:#c6a0f6,hl+:#ed8796"
export FZF_PREVIEW_OPTS="--preview
'([[ {} =~ ('.jpg'|'.jpeg'|'.png'|'.gif'|'.bmp'|'.svg'|'.mp4'|'.mkv')$ ]] && (chafa --center=on {} && exiftool {})) ||
([[ -f {} ]] && (bat --style=header,numbers,changes,plain --color=always --language=sh --line-range :500 {} || cat {})) ||
([[ -d {} ]] && (lsd -all --long --tree --depth=5 --group-dirs=first -I=.git {} )) || echo {} 3>/dev/null | head -n 500'
"
#'([[ \$(file -bL --mime-type {} 2> /dev/null = image) ]] && (catimg -w 100 {})) || # throwing an stb error cant silence
export FZF_PREVIEW_KEYBIND_OPTS="
--bind '?:toggle-preview'
--bind 'alt-?:preview(printf \"${FZF_SHOW_HELP_OPTS}\")'
--bind 'alt-j:preview-down'
--bind 'alt-k:preview-up'
--bind 'ctrl-d:preview-page-down'
--bind 'ctrl-u:preview-page-up'
--bind 'ctrl-t:preview-top'
--bind 'ctrl-b:preview-bottom'
--bind 'ctrl-l:clear-screen+clear-query+first'
--bind 'ctrl-space:change-preview-window(right,80%,nohidden|down,80%,border-top,nohidden|down,50%,nohidden|up,80%,border-down,nohidden|up,50%,nohidden|left,80%,nohidden|left,50%,nohidden|down:3:nohidden:wrap|up:3,nohidden:wrap|right,50%,nohidden)'
"
export FZF_KEYBIND_SHORTCUTS="
$FZF_PREVIEW_KEYBIND_OPTS
--bind 'alt-o:execute(xdg-open {+})'
--bind 'alt-s:toggle-sort'
--bind 'ctrl-/:execute(
if [[ -d {} ]]; then
broot {} < /dev/tty > /dev/tty 2>&1
elif [[ {} =~ ('.jpg'|'.jpeg'|'.png'|'.gif'|'.bmp'|'.svg'|'.mp4'|'.mkv')$ ]]; then
chafa --center {} | less > /dev/tty
else
bat --paging=always --style=plain --color=always --language=sh {} > /dev/tty
fi)'
--bind 'ctrl-a:select-all'
--bind 'ctrl-alt-d:deselect-all'
--bind 'ctrl-o:execute(flatpak run re.sonny.Junction {+})'
--bind 'ctrl-y:execute-silent(wl-copy {+})'
--bind 'ctrl-alt-y:execute-silent(readlink -f {+} | wl-copy)'
--bind 'ctrl-e:execute(${EDITOR} {} > /dev/tty)'
--bind 'ctrl-v:execute(code {+})'
--bind 'del:execute(rm -iv {};)+reload($FZF_DEFAULT_COMMAND)+clear-screen'
"
# --bind 'ctrl-/:execute(if [[ -f {} ]]; then bat --paging=always --style=\"header,numbers,changes\" --language=sh {} < /dev/tty > /dev/tty 2>&1; else broot {} < /dev/tty > /dev/tty 2>&1
# ; fi)'
export FZF_DEFAULT_COMMAND="fd --color=always --hidden --exclude .git"
export FZF_DEFAULT_OPTS="
"$FZF_PREVIEW_OPTS"
"$FZF_KEYBIND_SHORTCUTS"
"$FZF_THEME_CATPPUCCIN_MOCHA"
-i
--ansi
--multi
--height=90%
--info=inline
--no-separator
--layout=reverse
"
export FZF_ALT_C_COMMAND="fd --type=d --color=always --hidden --exclude .git"
export FZF_ALT_C_OPTS="
--preview 'lsd --all --long --tree --depth=3 {} | head -500'
--preview-window 'nohidden,<50(down,75%,border-top)'
--bind 'alt-h:reload(fd --type=d --color=always --follow --exclude .git)'
--bind 'alt-c:reload(fd -p ~ --color=always --hidden --type=d --follow)'
"
export FZF_CTRL_T_COMMAND="$FZF_DEFAULT_COMMAND"
export FZF_CTRL_T_OPTS="
--exit-0
--select-1
--info=default
--layout=reverse-list
--preview-window '50%,<50(up,75%,border-down)'
--header 'Alt-D: Directories | Alt-F: Files | Alt-H: Hide Files'
--bind 'alt-d:change-prompt( Directories > )+reload("$FZF_ALT_C_COMMAND")'
--bind 'alt-f:change-prompt( Files > )+reload("$FZF_DEFAULT_COMMAND")'
--bind 'alt-h:change-prompt( Hide Files > )+reload(fd --type=f --color=always --follow)'
--bind 'ctrl-t:change-prompt(Home > )+reload(fd --base-directory ~ --color=always --hidden --exclude .git)'
"
export FZF_CTRL_R_OPTS="
--preview 'echo {+} | bat --color=always --wrap never --language=sh --style=plain'
--preview-window 'down:3:nohidden:wrap'"
# export FZF_TMUX_OPTS='-p80% --color=border:blue'
# FZF_TMUX_CTRL_R_OPT="fzf-tmux -p $FZF_CTRL_R_OPTS"
# --bind 'alt-p:execute($'FZF_TMUX_OPTS'='-p90% --color=border:blue')'
# fzf completion '**' doesn't preview files (idk if it is a bug)
_fzf_compgen_path() {
fd --color=always --hidden --follow --exclude ".git" . "$1"
}
_fzf_compgen_dir() {
fd --color=always --type d --hidden --follow --exclude ".git" . "$1"
}

View file

@ -0,0 +1,16 @@
fzf-aliases-widget() {
LBUFFER="$LBUFFER$(FZF_DEFAULT_COMMAND=
alias | sed 's/=/ --- /' | \
awk -v blu=$(tput setaf 4) -v cyn=$(tput setaf 6) -v bld=$(tput bold) -v rst=$(tput sgr0) -F '---' \
'{
print bld cyn $1 rst blu "--" $2
}' | \
tr -d "'" | column -tl2 | \
fzf --prompt=" Aliases > " \
--preview 'echo {3..} | bat --color=always --plain --language=sh' \
--preview-window 'up:4:nohidden:wrap' | cut -d' ' -f 1)"
zle reset-prompt
}
zle -N fzf-aliases-widget
bindkey '^[a' fzf-aliases-widget #<Alt-A>

View file

@ -0,0 +1,25 @@
fzf-atuin-history-widget() {
local selected num
setopt localoptions noglobsubst noposixbuiltins pipefail no_aliases 2> /dev/null
selected=( $(atuin history list --cmd-only | tac | awk '{ cmd=$0; sub(/^[ \t]*[0-9]+\**[ \t]+/, "", cmd); if (!seen[cmd]++) print $0 }' | bat --color=always --wrap never --language=sh --style=plain |
FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} ${FZF_DEFAULT_OPTS-} --scheme=history --bind=ctrl-r:toggle-sort,ctrl-z:ignore ${FZF_CTRL_R_OPTS-} --query=${(qqq)LBUFFER} +m" $(__fzfcmd)) )
local ret=$?
if [ -n "$selected" ]; then
cmd=$selected[1,-1]
if [ -n "$cmd" ]; then
zle vi-fetch-history -n $cmd
fi
fi
zle -U "$cmd"
zle kill-buffer
zle reset-prompt
return $ret
}
if ! command -v atuin > /dev/null; then
zle -N fzf-history-widget
bindkey '^R' fzf-history-widget
else
zle -N fzf-atuin-history-widget
bindkey '^R' fzf-atuin-history-widget
fi

View file

@ -0,0 +1,15 @@
fzf-cd-recent-dir-widget () {
local dir
print -rNC1 -- $dirstack |
FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} --bind=ctrl-z:ignore ${FZF_DEFAULT_OPTS-} ${FZF_ALT_C_OPTS-}" $(__fzfcmd) +m \
--color=fg:bold:blue --query=${LBUFFER} --read0 --print0 |
IFS= read -rd '' dir
if [[ -n $dir ]]; then
BUFFER=" builtin cd -- $dir"
zle accept-line
fi
zle reset-prompt
}
zle -N fzf-cd-recent-dir-widget
bindkey '^[C' fzf-cd-recent-dir-widget #<Alt-Shift-C>

View file

@ -0,0 +1,20 @@
fzf-cd-widget() {
local cmd="${FZF_ALT_C_COMMAND:-"command find -L . -mindepth 1 \\( -path '*/\\.*' -o -fstype 'sysfs' -o -fstype 'devfs' -o -fstype 'devtmpfs' -o -fstype 'proc' \\) -prune \
-o -type d -print 2> /dev/null | cut -b3-"}"
setopt localoptions pipefail no_aliases 2> /dev/null
local dir="$(eval "$cmd" | FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} --reverse --bind=ctrl-z:ignore ${FZF_DEFAULT_OPTS-} ${FZF_ALT_C_OPTS-}" $(__fzfcmd) +m)"
if [[ -z "$dir" ]]; then
zle redisplay
return 0
fi
zle push-line # Clear buffer. Auto-restored on next prompt.
BUFFER=" builtin cd -- ${(q)dir}"
zle accept-line
local ret=$?
unset dir # ensure this doesn't end up appearing in prompt expansion
zle reset-prompt
return $ret
}
zle -N fzf-cd-widget
bindkey '^[c' fzf-cd-widget #<Alt-C>

View file

@ -0,0 +1,24 @@
fzf-dictionary-widget() {
local dict wiki wikis gogl
dict="dict {}"
wiki="wiki {} > /dev/tty"
wweb="w3m https://en.wikipedia.org/wiki/{}"
gogl="w3m https://google.com/search?q=define\ {}"
LBUFFER="$LBUFFER$(FZF_DEFAULT_COMMAND= cat /usr/share/dict/*words | sort | uniq -id | \
fzf-tmux \
-p60% \
--layout=default \
--header-first \
--header="M-w: Wiki | M-d: Define | M-g: Google" \
--color=fg:blue,fg+:blue,border:blue \
--bind="alt-d:change-preview($dict)" \
--bind="alt-w:execute($wiki)" \
--bind="alt-g:execute($gogl)" \
--prompt=" > " \
--preview "$dict" \
--preview-window='up,85%,border-bottom,wrap' | paste -sd" " -)"
zle reset-prompt
}
zle -N fzf-dictionary-widget
bindkey '^[d' fzf-dictionary-widget #<Alt-D>

View file

@ -0,0 +1,7 @@
function fzf-rg-widget() {
bash ${DOOTS:-$HOME/.local}/bin/fzf-rg-launcher "$LBUFFER"
zle redisplay
}
zle -N fzf-rg-widget
bindkey '^F' fzf-rg-widget

View file

@ -0,0 +1,13 @@
fzf-locate-widget() {
local selected
if selected=$(locate / | fzf --prompt " Locate > " -q "$LBUFFER" \
--bind 'alt-u:execute(sudo updatedb)' --header 'M-u: UpdateDB' \
--color=fg:bold:blue --preview-window '<50(down,75%,border-top)'
); then
LBUFFER=$selected
fi
zle reset-prompt
}
zle -N fzf-locate-widget
bindkey '^[i' fzf-locate-widget #<Alt-I>

View file

@ -0,0 +1,21 @@
fzf-man-widget() {
batman="man {1} | col -bx | bat --language=man --plain --color always --theme=\"Monokai Extended\""
man -k . | sort \
| awk -v CYN=${CYN} -v BLU=${BLU} -v RES=${RES} -v BLD=${BLD} '{ $1=CYN BLD $1; $2=RES BLU;} 1' \
| fzf \
-q "$LBUFFER" \
--ansi \
--tiebreak=begin \
--prompt=' Man > ' \
--header="M-u: update mandb | M-t: tl;dr | M-c: cheat.sh | M:m manual " \
--preview-window '50%,rounded,<50(down,80%,border-up)' \
--preview "${batman}" \
--bind "enter:execute(man {1})" \
--bind "alt-c:+change-preview(curl -s cht.sh/{1})+change-prompt(ﯽ Cheat > )" \
--bind "alt-m:+change-preview(${batman})+change-prompt( Man > )" \
--bind "alt-u:execute(sudo mandb && echo -e '\nUpdating tl;dr cache...';tldr --update)" \
--bind "alt-t:+change-preview(tldr --color=always {1})+change-prompt(ﳁ TLDR > )"
zle reset-prompt
}
zle -N fzf-man-widget
bindkey '^[h' fzf-man-widget

10
config/git/config Normal file
View file

@ -0,0 +1,10 @@
[user]
name = aleidk
email = ale.navarro.parra@gmail.com
[pull]
rebase = true
[init]
defaultBranch = main
[includeIf "gitdir:~/Repos/Work/"]
path = ~/.config/git/config-work

6
config/git/ignore Normal file
View file

@ -0,0 +1,6 @@
# Git Worktrees
.worktrees/*
# PHP Stuff
vendor
.php-cs-fixer.cache

View file

@ -0,0 +1,39 @@
#!/usr/bin/sh
if [ "x$XDG_SESSION_TYPE" = "xwayland" ] &&
[ "x$XDG_SESSION_CLASS" != "xgreeter" ] &&
[ -n "$SHELL" ] &&
grep -q "$SHELL" /etc/shells &&
! (echo "$SHELL" | grep -q "false") &&
! (echo "$SHELL" | grep -q "nologin"); then
if [ "$1" != '-l' ]; then
exec bash -c "exec -l '$SHELL' -c '$0 -l $*'"
else
shift
fi
fi
SETTING=$(G_MESSAGES_DEBUG='' gsettings get org.gnome.system.locale region)
REGION=${SETTING#\'}
REGION=${REGION%\'}
if [ -n "$REGION" ]; then
unset LC_TIME LC_NUMERIC LC_MONETARY LC_MEASUREMENT LC_PAPER
if [ "$LANG" != "$REGION" ]; then
# LC_CTYPE
export LC_NUMERIC=$REGION
export LC_TIME=$REGION
# LC_COLLATE
export LC_MONETARY=$REGION
# LC_MESSAGES
export LC_PAPER=$REGION
# LC_NAME
export LC_ADDRESS=$REGION
export LC_TELEPHONE=$REGION
export LC_MEASUREMENT=$REGION
# LC_IDENTIFICATION
fi
fi
exec Hyprland

158
config/hypr/hyprland.conf Normal file
View file

@ -0,0 +1,158 @@
#
# Please note not all available settings / options are set here.
# For a full list, see the wiki
#
# See https://wiki.hyprland.org/Configuring/Monitors/
monitor=,highrr,auto,1
# Execute your favorite apps at launch
exec-once = waybar & hyprpaper
# Source a file (multi-file configs)
# source = ~/.config/hypr/myColors.conf
# Some default env vars.
env = XCURSOR_SIZE,24
# For all categories, see https://wiki.hyprland.org/Configuring/Variables/
input {
kb_layout = latam
kb_variant =
kb_model =
kb_options = caps:escape
kb_rules =
follow_mouse = 1
touchpad {
natural_scroll = true
}
sensitivity = 0 # -1.0 - 1.0, 0 means no modification.
}
general {
# See https://wiki.hyprland.org/Configuring/Variables/ for more
gaps_in = 5
gaps_out = 10
border_size = 2
col.active_border = rgba(33ccffee) rgba(00ff99ee) 45deg
col.inactive_border = rgba(595959aa)
layout = dwindle
}
decoration {
# See https://wiki.hyprland.org/Configuring/Variables/ for more
rounding = 10
drop_shadow = true
shadow_range = 4
shadow_render_power = 3
col.shadow = rgba(1a1a1aee)
blur {
enabled = true
size = 3
passes = 1
new_optimizations = true
}
}
animations {
enabled = true
# Some default animations, see https://wiki.hyprland.org/Configuring/Animations/ for more
bezier = myBezier, 0.05, 0.9, 0.1, 1.05
animation = windows, 1, 7, myBezier
animation = windowsOut, 1, 7, default, popin 80%
animation = border, 1, 10, default
animation = borderangle, 1, 8, default
animation = fade, 1, 7, default
animation = workspaces, 1, 6, default
}
dwindle {
# See https://wiki.hyprland.org/Configuring/Dwindle-Layout/ for more
pseudotile = true # master switch for pseudotiling. Enabling is bound to mainMod + P in the keybinds section below
preserve_split = true # you probably want this
}
master {
# See https://wiki.hyprland.org/Configuring/Master-Layout/ for more
new_is_master = true
}
gestures {
# See https://wiki.hyprland.org/Configuring/Variables/ for more
workspace_swipe = true
workspace_swipe_invert = false
}
# Example per-device config
# See https://wiki.hyprland.org/Configuring/Keywords/#per-device-input-configs for more
device:epic-mouse-v1 {
sensitivity = -0.5
}
# Example windowrule v1
# windowrule = float, ^(kitty)$
# Example windowrule v2
# windowrulev2 = float,class:^(kitty)$,title:^(kitty)$
# See https://wiki.hyprland.org/Configuring/Window-Rules/ for more
# See https://wiki.hyprland.org/Configuring/Keywords/ for more
$mainMod = SUPER
# Example binds, see https://wiki.hyprland.org/Configuring/Binds/ for more
bind = $mainMod, Q, exec, alacritty
bind = $mainMod, C, killactive,
bind = $mainMod, M, exit,
bind = $mainMod, E, exec, dolphin
bind = $mainMod, V, togglefloating,
bind = $mainMod, D, exec, wofi --show drun
bind = $mainMod, P, pseudo, # dwindle
bind = $mainMod, J, togglesplit, # dwindle
# Move focus with mainMod + arrow keys
bind = $mainMod, h, movefocus, l
bind = $mainMod, j, movefocus, d
bind = $mainMod, k, movefocus, u
bind = $mainMod, l, movefocus, r
# Switch workspaces with mainMod + [0-9]
bind = $mainMod, 1, workspace, 1
bind = $mainMod, 2, workspace, 2
bind = $mainMod, 3, workspace, 3
bind = $mainMod, 4, workspace, 4
bind = $mainMod, 5, workspace, 5
bind = $mainMod, 6, workspace, 6
bind = $mainMod, 7, workspace, 7
bind = $mainMod, 8, workspace, 8
bind = $mainMod, 9, workspace, 9
bind = $mainMod, 0, workspace, 10
# Move active window to a workspace with mainMod + SHIFT + [0-9]
bind = $mainMod SHIFT, 1, movetoworkspace, 1
bind = $mainMod SHIFT, 2, movetoworkspace, 2
bind = $mainMod SHIFT, 3, movetoworkspace, 3
bind = $mainMod SHIFT, 4, movetoworkspace, 4
bind = $mainMod SHIFT, 5, movetoworkspace, 5
bind = $mainMod SHIFT, 6, movetoworkspace, 6
bind = $mainMod SHIFT, 7, movetoworkspace, 7
bind = $mainMod SHIFT, 8, movetoworkspace, 8
bind = $mainMod SHIFT, 9, movetoworkspace, 9
bind = $mainMod SHIFT, 0, movetoworkspace, 10
# Scroll through existing workspaces with mainMod + scroll
bind = $mainMod, mouse_down, workspace, e+1
bind = $mainMod, mouse_up, workspace, e-1
# Move/resize windows with mainMod + LMB/RMB and dragging
bindm = $mainMod, mouse:272, movewindow
bindm = $mainMod, mouse:273, resizewindow

View file

@ -0,0 +1,4 @@
preload = ~/Pictures/wallpaper.jpg
#set the default wallpaper(s) seen on inital workspace(s) --depending on the number of monitors used
wallpaper = ,~/Pictures/wallpaper.jpg

View file

@ -0,0 +1,80 @@
# vim:ft=kitty
## name: Catppuccin-Macchiato
## author: Pocco81 (https://github.com/Pocco81)
## license: MIT
## upstream: https://github.com/catppuccin/kitty/blob/main/macchiato.conf
## blurb: Soothing pastel theme for the high-spirited!
# The basic colors
foreground #CAD3F5
background #24273A
selection_foreground #24273A
selection_background #F4DBD6
# Cursor colors
cursor #F4DBD6
cursor_text_color #24273A
# URL underline color when hovering with mouse
url_color #F4DBD6
# Kitty window border colors
active_border_color #B7BDF8
inactive_border_color #6E738D
bell_border_color #EED49F
# OS Window titlebar colors
wayland_titlebar_color system
macos_titlebar_color system
# Tab bar colors
active_tab_foreground #181926
active_tab_background #C6A0F6
inactive_tab_foreground #CAD3F5
inactive_tab_background #1E2030
tab_bar_background #181926
# Colors for marks (marked text in the terminal)
mark1_foreground #24273A
mark1_background #B7BDF8
mark2_foreground #24273A
mark2_background #C6A0F6
mark3_foreground #24273A
mark3_background #7DC4E4
# The 16 terminal colors
# black
color0 #494D64
color8 #5B6078
# red
color1 #ED8796
color9 #ED8796
# green
color2 #A6DA95
color10 #A6DA95
# yellow
color3 #EED49F
color11 #EED49F
# blue
color4 #8AADF4
color12 #8AADF4
# magenta
color5 #F5BDE6
color13 #F5BDE6
# cyan
color6 #8BD5CA
color14 #8BD5CA
# white
color7 #B8C0E0
color15 #A5ADCB

2458
config/kitty/kitty.conf Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

575
config/lazygit/config.yml Normal file
View file

@ -0,0 +1,575 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/jesseduffield/lazygit/master/schema/config.json
# Config relating to the Lazygit UI
gui:
# The number of lines you scroll by when scrolling the main window
scrollHeight: 2
# If true, allow scrolling past the bottom of the content in the main window
scrollPastBottom: true
# See https://github.com/jesseduffield/lazygit/blob/master/docs/Config.md#scroll-off-margin
scrollOffMargin: 2
# One of: 'margin' (default) | 'jump'
scrollOffBehavior: margin
# If true, capture mouse events.
# When mouse events are captured, it's a little harder to select text: e.g. requiring you to hold the option key when on macOS.
mouseEvents: true
# If true, do not show a warning when discarding changes in the staging view.
skipDiscardChangeWarning: false
# If true, do not show warning when applying/popping the stash
skipStashWarning: false
# If true, do not show a warning when attempting to commit without any staged files; instead stage all unstaged files.
skipNoStagedFilesWarning: false
# If true, do not show a warning when rewording a commit via an external editor
skipRewordInEditorWarning: false
# Fraction of the total screen width to use for the left side section. You may want to pick a small number (e.g. 0.2) if you're using a narrow screen, so that you can see more of the main section.
# Number from 0 to 1.0.
sidePanelWidth: 0.3333
# If true, increase the height of the focused side window; creating an accordion effect.
expandFocusedSidePanel: false
# The weight of the expanded side panel, relative to the other panels. 2 means
# twice as tall as the other panels. Only relevant if `expandFocusedSidePanel` is true.
expandedSidePanelWeight: 2
# Sometimes the main window is split in two (e.g. when the selected file has both staged and unstaged changes). This setting controls how the two sections are split.
# Options are:
# - 'horizontal': split the window horizontally
# - 'vertical': split the window vertically
# - 'flexible': (default) split the window horizontally if the window is wide enough, otherwise split vertically
mainPanelSplitMode: flexible
# How the window is split when in half screen mode (i.e. after hitting '+' once).
# Possible values:
# - 'left': split the window horizontally (side panel on the left, main view on the right)
# - 'top': split the window vertically (side panel on top, main view below)
enlargedSideViewLocation: left
# One of 'auto' (default) | 'en' | 'zh-CN' | 'zh-TW' | 'pl' | 'nl' | 'ja' | 'ko' | 'ru'
language: auto
# Format used when displaying time e.g. commit time.
# Uses Go's time format syntax: https://pkg.go.dev/time#Time.Format
timeFormat: 02 Jan 06
# Format used when displaying time if the time is less than 24 hours ago.
# Uses Go's time format syntax: https://pkg.go.dev/time#Time.Format
shortTimeFormat: 3:04PM
# Config relating to colors and styles.
# See https://github.com/jesseduffield/lazygit/blob/master/docs/Config.md#color-attributes
theme:
activeBorderColor:
- '#8bd5ca'
- bold
inactiveBorderColor:
- '#a5adcb'
optionsTextColor:
- '#8aadf4'
selectedLineBgColor:
- '#363a4f'
cherryPickedCommitBgColor:
- '#494d64'
cherryPickedCommitFgColor:
- '#8bd5ca'
unstagedChangesColor:
- '#ed8796'
defaultFgColor:
- '#cad3f5'
searchingActiveBorderColor:
- '#eed49f'
# Background color of selected line when view doesn't have focus.
inactiveViewSelectedLineBgColor:
- bold
# Foreground color of marked base commit (for rebase)
markedBaseCommitFgColor:
- blue
# Background color of marked base commit (for rebase)
markedBaseCommitBgColor:
- yellow
authorColors:
'*': '#b7bdf8'
# Config relating to the commit length indicator
commitLength:
# If true, show an indicator of commit message length
show: true
# If true, show the '5 of 20' footer at the bottom of list views
showListFooter: true
# If true, display the files in the file views as a tree. If false, display the files as a flat list.
# This can be toggled from within Lazygit with the '~' key, but that will not change the default.
showFileTree: true
# If true, show a random tip in the command log when Lazygit starts
showRandomTip: true
# If true, show the command log
showCommandLog: true
# If true, show the bottom line that contains keybinding info and useful buttons. If false, this line will be hidden except to display a loader for an in-progress action.
showBottomLine: true
# If true, show jump-to-window keybindings in window titles.
showPanelJumps: true
# Deprecated: use nerdFontsVersion instead
showIcons: false
# Nerd fonts version to use.
# One of: '2' | '3' | empty string (default)
# If empty, do not show icons.
nerdFontsVersion: "3"
# If true (default), file icons are shown in the file views. Only relevant if NerdFontsVersion is not empty.
showFileIcons: true
# Length of author name in (non-expanded) commits view. 2 means show initials only.
commitAuthorShortLength: 2
# Length of author name in expanded commits view. 2 means show initials only.
commitAuthorLongLength: 17
# Length of commit hash in commits view. 0 shows '*' if NF icons aren't on.
commitHashLength: 8
# If true, show commit hashes alongside branch names in the branches view.
showBranchCommitHash: false
# Whether to show the divergence from the base branch in the branches view.
# One of: 'none' | 'onlyArrow' | 'arrowAndNumber'
showDivergenceFromBaseBranch: none
# Height of the command log view
commandLogSize: 8
# Whether to split the main window when viewing file changes.
# One of: 'auto' | 'always'
# If 'auto', only split the main window when a file has both staged and unstaged changes
splitDiff: auto
# Default size for focused window. Window size can be changed from within Lazygit with '+' and '_' (but this won't change the default).
# One of: 'normal' (default) | 'half' | 'full'
windowSize: normal
# Window border style.
# One of 'rounded' (default) | 'single' | 'double' | 'hidden'
border: rounded
# If true, show a seriously epic explosion animation when nuking the working tree.
animateExplosion: true
# Whether to stack UI components on top of each other.
# One of 'auto' (default) | 'always' | 'never'
portraitMode: auto
# How things are filtered when typing '/'.
# One of 'substring' (default) | 'fuzzy'
filterMode: fuzzy
# Config relating to the spinner.
spinner:
# The frames of the spinner animation.
frames:
- '|'
- /
- '-'
- \
# The "speed" of the spinner in milliseconds.
rate: 50
# Status panel view.
# One of 'dashboard' (default) | 'allBranchesLog'
statusPanelView: dashboard
# If true, jump to the Files panel after popping a stash
switchToFilesAfterStashPop: true
# If true, jump to the Files panel after applying a stash
switchToFilesAfterStashApply: true
# Config relating to git
git:
# See https://github.com/jesseduffield/lazygit/blob/master/docs/Custom_Pagers.md
paging:
# Value of the --color arg in the git diff command. Some pagers want this to be set to 'always' and some want it set to 'never'
colorArg: always
# e.g.
# diff-so-fancy
# delta --dark --paging=never
# ydiff -p cat -s --wrap --width={{columnWidth}}
pager: ""
# If true, Lazygit will use whatever pager is specified in `$GIT_PAGER`, `$PAGER`, or your *git config*. If the pager ends with something like ` | less` we will strip that part out, because less doesn't play nice with our rendering approach. If the custom pager uses less under the hood, that will also break rendering (hence the `--paging=never` flag for the `delta` pager).
useConfig: true
# e.g. 'difft --color=always'
externalDiffCommand: ""
# Config relating to committing
commit:
# If true, pass '--signoff' flag when committing
signOff: false
# Automatic WYSIWYG wrapping of the commit message as you type
autoWrapCommitMessage: true
# If autoWrapCommitMessage is true, the width to wrap to
autoWrapWidth: 72
# Config relating to merging
merging:
# If true, run merges in a subprocess so that if a commit message is required, Lazygit will not hang
# Only applicable to unix users.
manualCommit: false
# Extra args passed to `git merge`, e.g. --no-ff
args: ""
# The commit message to use for a squash merge commit. Can contain "{{selectedRef}}" and "{{currentBranch}}" placeholders.
squashMergeMessage: Squash merge {{selectedRef}} into {{currentBranch}}
# list of branches that are considered 'main' branches, used when displaying commits
mainBranches:
- master
- main
# Prefix to use when skipping hooks. E.g. if set to 'WIP', then pre-commit hooks will be skipped when the commit message starts with 'WIP'
skipHookPrefix: WIP
# If true, periodically fetch from remote
autoFetch: true
# If true, periodically refresh files and submodules
autoRefresh: true
# If true, pass the --all arg to git fetch
fetchAll: true
# If true, lazygit will automatically stage files that used to have merge
# conflicts but no longer do; and it will also ask you if you want to
# continue a merge or rebase if you've resolved all conflicts. If false, it
# won't do either of these things.
autoStageResolvedConflicts: true
# Command used when displaying the current branch git log in the main window
branchLogCmd: git log --graph --color=always --abbrev-commit --decorate --date=relative --pretty=medium {{branchName}} --
# Command used to display git log of all branches in the main window.
# Deprecated: User `allBranchesLogCmds` instead.
allBranchesLogCmd: git log --graph --all --color=always --abbrev-commit --decorate --date=relative --pretty=medium
# If true, do not spawn a separate process when using GPG
overrideGpg: false
# If true, do not allow force pushes
disableForcePushing: false
# See https://github.com/jesseduffield/lazygit/blob/master/docs/Config.md#predefined-commit-message-prefix
commitPrefix:
# pattern to match on. E.g. for 'feature/AB-123' to match on the AB-123 use "^\\w+\\/(\\w+-\\w+).*"
pattern: ""
# Replace directive. E.g. for 'feature/AB-123' to start the commit message with 'AB-123 ' use "[$1] "
replace: ""
# See https://github.com/jesseduffield/lazygit/blob/master/docs/Config.md#predefined-branch-name-prefix
branchPrefix: ""
# If true, parse emoji strings in commit messages e.g. render :rocket: as 🚀
# (This should really be under 'gui', not 'git')
parseEmoji: true
# Config for showing the log in the commits view
log:
# One of: 'date-order' | 'author-date-order' | 'topo-order' | 'default'
# 'topo-order' makes it easier to read the git log graph, but commits may not
# appear chronologically. See https://git-scm.com/docs/
#
# Deprecated: Configure this with `Log menu -> Commit sort order` (<c-l> in the commits window by default).
order: topo-order
# This determines whether the git graph is rendered in the commits panel
# One of 'always' | 'never' | 'when-maximised'
#
# Deprecated: Configure this with `Log menu -> Show git graph` (<c-l> in the commits window by default).
showGraph: always
# displays the whole git graph by default in the commits view (equivalent to passing the `--all` argument to `git log`)
showWholeGraph: false
# When copying commit hashes to the clipboard, truncate them to this
# length. Set to 40 to disable truncation.
truncateCopiedCommitHashesTo: 12
# Periodic update checks
update:
# One of: 'prompt' (default) | 'background' | 'never'
method: prompt
# Period in days between update checks
days: 14
# Background refreshes
refresher:
# File/submodule refresh interval in seconds.
# Auto-refresh can be disabled via option 'git.autoRefresh'.
refreshInterval: 10
# Re-fetch interval in seconds.
# Auto-fetch can be disabled via option 'git.autoFetch'.
fetchInterval: 60
# If true, show a confirmation popup before quitting Lazygit
confirmOnQuit: false
# If true, exit Lazygit when the user presses escape in a context where there is nothing to cancel/close
quitOnTopLevelReturn: true
# Config relating to things outside of Lazygit like how files are opened, copying to clipboard, etc
os:
# Command for editing a file. Should contain "{{filename}}".
edit: ""
# Command for editing a file at a given line number. Should contain
# "{{filename}}", and may optionally contain "{{line}}".
editAtLine: ""
# Same as EditAtLine, except that the command needs to wait until the
# window is closed.
editAtLineAndWait: ""
# For opening a directory in an editor
openDirInEditor: ""
# A built-in preset that sets all of the above settings. Supported presets
# are defined in the getPreset function in editor_presets.go.
editPreset: "nvim-remote"
# Command for opening a file, as if the file is double-clicked. Should
# contain "{{filename}}", but doesn't support "{{line}}".
open: "xdg-open {{filename}} >/dev/null"
# Command for opening a link. Should contain "{{link}}".
openLink: ""
# EditCommand is the command for editing a file.
# Deprecated: use Edit instead. Note that semantics are different:
# EditCommand is just the command itself, whereas Edit contains a
# "{{filename}}" variable.
editCommand: ""
# EditCommandTemplate is the command template for editing a file
# Deprecated: use EditAtLine instead.
editCommandTemplate: ""
# OpenCommand is the command for opening a file
# Deprecated: use Open instead.
openCommand: ""
# OpenLinkCommand is the command for opening a link
# Deprecated: use OpenLink instead.
openLinkCommand: ""
# CopyToClipboardCmd is the command for copying to clipboard.
# See https://github.com/jesseduffield/lazygit/blob/master/docs/Config.md#custom-command-for-copying-to-and-pasting-from-clipboard
copyToClipboardCmd: ""
# ReadFromClipboardCmd is the command for reading the clipboard.
# See https://github.com/jesseduffield/lazygit/blob/master/docs/Config.md#custom-command-for-copying-to-and-pasting-from-clipboard
readFromClipboardCmd: ""
# If true, don't display introductory popups upon opening Lazygit.
disableStartupPopups: false
# What to do when opening Lazygit outside of a git repo.
# - 'prompt': (default) ask whether to initialize a new repo or open in the most recent repo
# - 'create': initialize a new repo
# - 'skip': open most recent repo
# - 'quit': exit Lazygit
notARepository: quit
# If true, display a confirmation when subprocess terminates. This allows you to view the output of the subprocess before returning to Lazygit.
promptToReturnFromSubprocess: true
# Keybindings
keybinding:
universal:
quit: q
quit-alt1: <c-c>
return: <esc>
quitWithoutChangingDirectory: Q
togglePanel: <tab>
prevItem: <up>
nextItem: <down>
prevItem-alt: k
nextItem-alt: j
prevPage: ','
nextPage: .
scrollLeft: H
scrollRight: L
gotoTop: <
gotoBottom: '>'
toggleRangeSelect: v
rangeSelectDown: <s-down>
rangeSelectUp: <s-up>
prevBlock: <left>
nextBlock: <right>
prevBlock-alt: h
nextBlock-alt: l
nextBlock-alt2: <tab>
prevBlock-alt2: <backtab>
jumpToBlock:
- "1"
- "2"
- "3"
- "4"
- "5"
nextMatch: "n"
prevMatch: "N"
startSearch: /
optionMenu: <disabled>
optionMenu-alt1: '?'
select: <space>
goInto: <enter>
confirm: <enter>
confirmInEditor: <a-enter>
remove: d
new: "n"
edit: e
openFile: o
scrollUpMain: <pgup>
scrollDownMain: <pgdown>
scrollUpMain-alt1: K
scrollDownMain-alt1: J
scrollUpMain-alt2: <c-u>
scrollDownMain-alt2: <c-d>
executeShellCommand: ':'
createRebaseOptionsMenu: m
# 'Files' appended for legacy reasons
pushFiles: P
# 'Files' appended for legacy reasons
pullFiles: p
refresh: R
createPatchOptionsMenu: <c-p>
nextTab: ']'
prevTab: '['
nextScreenMode: +
prevScreenMode: _
undo: z
redo: <c-z>
filteringMenu: <c-s>
diffingMenu: W
diffingMenu-alt: <c-e>
copyToClipboard: <c-o>
openRecentRepos: <c-r>
submitEditorText: <enter>
extrasMenu: '@'
toggleWhitespaceInDiffView: <c-w>
increaseContextInDiffView: '}'
decreaseContextInDiffView: '{'
increaseRenameSimilarityThreshold: )
decreaseRenameSimilarityThreshold: (
openDiffTool: <c-t>
status:
checkForUpdate: u
recentRepos: <enter>
allBranchesLogGraph: a
files:
commitChanges: c
commitChangesWithoutHook: w
amendLastCommit: A
commitChangesWithEditor: C
findBaseCommitForFixup: <c-f>
confirmDiscard: x
ignoreFile: i
refreshFiles: r
stashAllChanges: s
viewStashOptions: S
toggleStagedAll: a
viewResetOptions: D
fetch: f
toggleTreeView: '`'
openMergeTool: M
openStatusFilter: <c-b>
copyFileInfoToClipboard: "y"
branches:
createPullRequest: o
viewPullRequestOptions: O
copyPullRequestURL: <c-y>
checkoutBranchByName: c
forceCheckoutBranch: F
rebaseBranch: r
renameBranch: R
mergeIntoCurrentBranch: M
viewGitFlowOptions: i
fastForward: f
createTag: T
pushTag: P
setUpstream: u
fetchRemote: f
sortOrder: s
worktrees:
viewWorktreeOptions: w
commits:
squashDown: s
renameCommit: r
renameCommitWithEditor: R
viewResetOptions: g
markCommitAsFixup: f
createFixupCommit: F
squashAboveCommits: S
moveDownCommit: <c-j>
moveUpCommit: <c-k>
amendToCommit: A
resetCommitAuthor: a
pickCommit: p
revertCommit: t
cherryPickCopy: C
pasteCommits: V
markCommitAsBaseForRebase: B
tagCommit: T
checkoutCommit: <space>
resetCherryPick: <c-R>
copyCommitAttributeToClipboard: "y"
openLogMenu: <c-l>
openInBrowser: o
viewBisectOptions: b
startInteractiveRebase: i
amendAttribute:
resetAuthor: a
setAuthor: A
addCoAuthor: c
stash:
popStash: g
renameStash: r
commitFiles:
checkoutCommitFile: c
main:
toggleSelectHunk: a
pickBothHunks: b
editSelectHunk: E
submodules:
init: i
update: u
bulkMenu: b
commitMessage:
commitMenu: <c-o>

11
config/mako/config Normal file
View file

@ -0,0 +1,11 @@
default-timeout=5000
# Colors
background-color=#24273a
text-color=#cad3f5
border-color=#8aadf4
progress-color=over #363a4f
[urgency=high]
border-color=#f5a97f

11
config/mise/config.toml Normal file
View file

@ -0,0 +1,11 @@
[tools]
node = 'lts'
# python = {version='3', virtualenv='.venv'}
python = {version='3'} # setting virtualenv adds a virtualenv in every directory
php = "8.2"
go = "latest"
[settings]
[alias.node]
my_custom_node = '20' # makes `rtx install node@my_custom_node` install node-20.x
# this can also be specified in a plugin (see below in "Aliases")

155
config/mpv/encoding.rst Normal file
View file

@ -0,0 +1,155 @@
General usage
=============
::
mpv infile -o outfile [-of outfileformat] [-ofopts formatoptions] [-orawts] \
[(any other mpv options)] \
-ovc outvideocodec [-ovcopts outvideocodecoptions] \
-oac outaudiocodec [-oacopts outaudiocodecoptions]
Help for these options is provided if giving help as parameter, as in::
mpv -ovc help
The suboptions of these generally are identical to ffmpeg's (as option parsing
is simply delegated to ffmpeg). The option -ocopyts enables copying timestamps
from the source as-is, instead of fixing them to match audio playback time
(note: this doesn't work with all output container formats); -orawts even turns
off discontinuity fixing.
Note that if neither -ofps nor -oautofps is specified, VFR encoding is assumed
and the time base is 24000fps. -oautofps sets -ofps to a guessed fps number
from the input video. Note that not all codecs and not all formats support VFR
encoding, and some which do have bugs when a target bitrate is specified - use
-ofps or -oautofps to force CFR encoding in these cases.
Of course, the options can be stored in a profile, like this .config/mpv/mpv.conf
section::
[myencprofile]
vf-add = scale=480:-2
ovc = libx264
ovcopts-add = preset=medium
ovcopts-add = tune=fastdecode
ovcopts-add = crf=23
ovcopts-add = maxrate=1500k
ovcopts-add = bufsize=1000k
ovcopts-add = rc_init_occupancy=900k
ovcopts-add = refs=2
ovcopts-add = profile=baseline
oac = aac
oacopts-add = b=96k
It's also possible to define default encoding options by putting them into
the section named ``[encoding]``. (This behavior changed after mpv 0.3.x. In
mpv 0.3.x, config options in the default section / no section were applied
to encoding. This is not the case anymore.)
One can then encode using this profile using the command::
mpv infile -o outfile.mp4 -profile myencprofile
Some example profiles are provided in a file
etc/encoding-profiles.conf; as for this, see below.
Encoding examples
=================
These are some examples of encoding targets this code has been used and tested
for.
Typical MPEG-4 Part 2 ("ASP", "DivX") encoding, AVI container::
mpv infile -o outfile.avi \
--vf=fps=25 \
-ovc mpeg4 -ovcopts qscale=4 \
-oac libmp3lame -oacopts ab=128k
Note: AVI does not support variable frame rate, so the fps filter must be used.
The frame rate should ideally match the input (25 for PAL, 24000/1001 or
30000/1001 for NTSC)
Typical MPEG-4 Part 10 ("AVC", "H.264") encoding, Matroska (MKV) container::
mpv infile -o outfile.mkv \
-ovc libx264 -ovcopts preset=medium,crf=23,profile=baseline \
-oac libvorbis -oacopts qscale=3
Typical MPEG-4 Part 10 ("AVC", "H.264") encoding, MPEG-4 (MP4) container::
mpv infile -o outfile.mp4 \
-ovc libx264 -ovcopts preset=medium,crf=23,profile=baseline \
-oac aac -oacopts ab=128k
Typical VP8 encoding, WebM (restricted Matroska) container::
mpv infile -o outfile.mkv \
-of webm \
-ovc libvpx -ovcopts qmin=6,b=1000000k \
-oac libvorbis -oacopts qscale=3
Device targets
==============
As the options for various devices can get complex, profiles can be used.
An example profile file for encoding is provided in
etc/encoding-profiles.conf in the source tree. This file is installed and loaded
by default. If you want to modify it, you can replace and it with your own copy
by doing::
mkdir -p ~/.mpv
cp /etc/mpv/encoding-profiles.conf ~/.mpv/encoding-profiles.conf
Keep in mind that the default profile is the playback one. If you want to add
options that apply only in encoding mode, put them into a ``[encoding]``
section.
Refer to the top of that file for more comments - in a nutshell, the following
options are added by it::
-profile enc-to-dvdpal DVD-Video PAL, use dvdauthor -v pal+4:3 -a ac3+en
-profile enc-to-dvdntsc DVD-Video NTSC, use dvdauthor -v ntsc+4:3 -a ac3+en
-profile enc-to-bb-9000 MP4 for Blackberry Bold 9000
-profile enc-to-nok-6300 3GP for Nokia 6300
-profile enc-to-psp MP4 for PlayStation Portable
-profile enc-to-iphone MP4 for iPhone
-profile enc-to-iphone-4 MP4 for iPhone 4 (double res)
-profile enc-to-iphone-5 MP4 for iPhone 5 (even larger res)
You can encode using these with a command line like::
mpv infile -o outfile.mp4 -profile enc-to-bb-9000
Of course, you are free to override options set by these profiles by specifying
them after the -profile option.
What works
==========
* Encoding at variable frame rate (default)
* Encoding at constant frame rate using --vf=fps=RATE
* 2-pass encoding (specify flags=+pass1 in the first pass's -ovcopts, specify
flags=+pass2 in the second pass)
* Hardcoding subtitles using vobsub, ass or srt subtitle rendering (just
configure mpv for the subtitles as usual)
* Hardcoding any other mpv OSD (e.g. time codes, using -osdlevel 3 and -vf
expand=::::1)
* Encoding directly from a DVD, network stream, webcam, or any other source
mpv supports
* Using x264 presets/tunings/profiles (by using profile=, tune=, preset= in the
-ovcopts)
* Deinterlacing/Inverse Telecine with any of mpv's filters for that
* Audio file converting: mpv -o outfile.mp3 infile.flac -no-video -oac
libmp3lame -oacopts ab=320k
What does not work yet
======================
* 3-pass encoding (ensuring constant total size and bitrate constraints while
having VBR audio; mencoder calls this "frameno")
* Direct stream copy

191
config/mpv/input.conf Normal file
View file

@ -0,0 +1,191 @@
# mpv keybindings
#
# Location of user-defined bindings: ~/.config/mpv/input.conf
#
# Lines starting with # are comments. Use SHARP to assign the # key.
# Copy this file and uncomment and edit the bindings you want to change.
#
# List of commands and further details: DOCS/man/input.rst
# List of special keys: --input-keylist
# Keybindings testing mode: mpv --input-test --force-window --idle
#
# Use 'ignore' to unbind a key fully (e.g. 'ctrl+a ignore').
#
# Strings need to be quoted and escaped:
# KEY show-text "This is a single backslash: \\ and a quote: \" !"
#
# You can use modifier-key combinations like Shift+Left or Ctrl+Alt+x with
# the modifiers Shift, Ctrl, Alt and Meta (may not work on the terminal).
#
# The default keybindings are hardcoded into the mpv binary.
# You can disable them completely with: --no-input-default-bindings
# Developer note:
# On compilation, this file is baked into the mpv binary, and all lines are
# uncommented (unless '#' is followed by a space) - thus this file defines the
# default key bindings.
# If this is enabled, treat all the following bindings as default.
#default-bindings start
#MBTN_LEFT ignore # don't do anything
#MBTN_LEFT_DBL cycle fullscreen # toggle fullscreen
#MBTN_RIGHT cycle pause # toggle pause/playback mode
#MBTN_BACK playlist-prev # skip to the previous file
#MBTN_FORWARD playlist-next # skip to the next file
# Mouse wheels, touchpad or other input devices that have axes
# if the input devices supports precise scrolling it will also scale the
# numeric value accordingly
#WHEEL_UP seek 10 # seek 10 seconds forward
#WHEEL_DOWN seek -10 # seek 10 seconds backward
#WHEEL_LEFT add volume -2
#WHEEL_RIGHT add volume 2
## Seek units are in seconds, but note that these are limited by keyframes
#RIGHT seek 5 # seek 5 seconds forward
#LEFT seek -5 # seek 5 seconds backward
#UP seek 60 # seek 1 minute forward
#DOWN seek -60 # seek 1 minute backward
# Do smaller, always exact (non-keyframe-limited), seeks with shift.
# Don't show them on the OSD (no-osd).
#Shift+RIGHT no-osd seek 1 exact # seek exactly 1 second forward
#Shift+LEFT no-osd seek -1 exact # seek exactly 1 second backward
#Shift+UP no-osd seek 5 exact # seek exactly 5 seconds forward
#Shift+DOWN no-osd seek -5 exact # seek exactly 5 seconds backward
#Ctrl+LEFT no-osd sub-seek -1 # seek to the previous subtitle
#Ctrl+RIGHT no-osd sub-seek 1 # seek to the next subtitle
#Ctrl+Shift+LEFT sub-step -1 # change subtitle timing such that the previous subtitle is displayed
#Ctrl+Shift+RIGHT sub-step 1 # change subtitle timing such that the next subtitle is displayed
#Alt+left add video-pan-x 0.1 # move the video right
#Alt+right add video-pan-x -0.1 # move the video left
#Alt+up add video-pan-y 0.1 # move the video down
#Alt+down add video-pan-y -0.1 # move the video up
#Alt++ add video-zoom 0.1 # zoom in
#Alt+- add video-zoom -0.1 # zoom out
#Alt+BS set video-zoom 0 ; set video-pan-x 0 ; set video-pan-y 0 # reset zoom and pan settings
#PGUP add chapter 1 # seek to the next chapter
#PGDWN add chapter -1 # seek to the previous chapter
#Shift+PGUP seek 600 # seek 10 minutes forward
#Shift+PGDWN seek -600 # seek 10 minutes backward
#[ multiply speed 1/1.1 # decrease the playback speed
#] multiply speed 1.1 # increase the playback speed
#{ multiply speed 0.5 # halve the playback speed
#} multiply speed 2.0 # double the playback speed
#BS set speed 1.0 # reset the speed to normal
#Shift+BS revert-seek # undo the previous (or marked) seek
#Shift+Ctrl+BS revert-seek mark # mark the position for revert-seek
#q quit
#Q quit-watch-later # exit and remember the playback position
#q {encode} quit 4
#ESC set fullscreen no # leave fullscreen
#ESC {encode} quit 4
#p cycle pause # toggle pause/playback mode
#. frame-step # advance one frame and pause
#, frame-back-step # go back by one frame and pause
#SPACE cycle pause # toggle pause/playback mode
#> playlist-next # skip to the next file
#ENTER playlist-next # skip to the next file
#< playlist-prev # skip to the previous file
#O no-osd cycle-values osd-level 3 1 # toggle displaying the OSD on user interaction or always
#o show-progress # show playback progress
#P show-progress # show playback progress
#i script-binding stats/display-stats # display information and statistics
#I script-binding stats/display-stats-toggle # toggle displaying information and statistics
#` script-binding console/enable # open the console
#z add sub-delay -0.1 # shift subtitles 100 ms earlier
#Z add sub-delay +0.1 # delay subtitles by 100 ms
#x add sub-delay +0.1 # delay subtitles by 100 ms
#ctrl++ add audio-delay 0.100 # change audio/video sync by delaying the audio
#ctrl+- add audio-delay -0.100 # change audio/video sync by shifting the audio earlier
#Shift+g add sub-scale +0.1 # increase the subtitle font size
#Shift+f add sub-scale -0.1 # decrease the subtitle font size
#9 add volume -2
#/ add volume -2
#0 add volume 2
#* add volume 2
#m cycle mute # toggle mute
#1 add contrast -1
#2 add contrast 1
#3 add brightness -1
#4 add brightness 1
#5 add gamma -1
#6 add gamma 1
#7 add saturation -1
#8 add saturation 1
#Alt+0 set current-window-scale 0.5 # halve the window size
#Alt+1 set current-window-scale 1.0 # reset the window size
#Alt+2 set current-window-scale 2.0 # double the window size
#d cycle deinterlace # toggle the deinterlacing filter
#r add sub-pos -1 # move subtitles up
#R add sub-pos +1 # move subtitles down
#t add sub-pos +1 # move subtitles down
#v cycle sub-visibility # hide or show the subtitles
#Alt+v cycle secondary-sub-visibility # hide or show the secondary subtitles
#V cycle sub-ass-vsfilter-aspect-compat # toggle stretching SSA/ASS subtitles with anamorphic videos to match the historical renderer
#u cycle-values sub-ass-override "force" "no" # toggle overriding SSA/ASS subtitle styles with the normal styles
#j cycle sub # switch subtitle track
#J cycle sub down # switch subtitle track backwards
#SHARP cycle audio # switch audio track
#_ cycle video # switch video track
#T cycle ontop # toggle placing the video on top of other windows
#f cycle fullscreen # toggle fullscreen
#s screenshot # take a screenshot of the video in its original resolution with subtitles
#S screenshot video # take a screenshot of the video in its original resolution without subtitles
#Ctrl+s screenshot window # take a screenshot of the window with OSD and subtitles
#Alt+s screenshot each-frame # automatically screenshot every frame; issue this command again to stop taking screenshots
#w add panscan -0.1 # decrease panscan
#W add panscan +0.1 # shrink black bars by cropping the video
#e add panscan +0.1 # shrink black bars by cropping the video
#A cycle-values video-aspect-override "16:9" "4:3" "2.35:1" "-1" # cycle the video aspect ratio ("-1" is the container aspect)
#POWER quit
#PLAY cycle pause # toggle pause/playback mode
#PAUSE cycle pause # toggle pause/playback mode
#PLAYPAUSE cycle pause # toggle pause/playback mode
#PLAYONLY set pause no # unpause
#PAUSEONLY set pause yes # pause
#STOP quit
#FORWARD seek 60 # seek 1 minute forward
#REWIND seek -60 # seek 1 minute backward
#NEXT playlist-next # skip to the next file
#PREV playlist-prev # skip to the previous file
#VOLUME_UP add volume 2
#VOLUME_DOWN add volume -2
#MUTE cycle mute # toggle mute
#CLOSE_WIN quit
#CLOSE_WIN {encode} quit 4
#ctrl+w quit
#E cycle edition # switch edition
#l ab-loop # set/clear A-B loop points
#L cycle-values loop-file "inf" "no" # toggle infinite looping
#ctrl+c quit 4
#DEL script-binding osc/visibility # cycle OSC visibility between never, auto (mouse-move) and always
#ctrl+h cycle-values hwdec "auto" "no" # toggle hardware decoding
#F8 show-text ${playlist} # show the playlist
#F9 show-text ${track-list} # show the list of video, audio and sub tracks
#
# Legacy bindings (may or may not be removed in the future)
#
#! add chapter -1 # seek to the previous chapter
#@ add chapter 1 # seek to the next chapter
#
# Not assigned by default
# (not an exhaustive list of unbound commands)
#
# ? cycle sub-forced-only # toggle DVD forced subs
# ? stop # stop playback (quit or enter idle mode)
### Shaders ###
CTRL+1 no-osd change-list glsl-shaders set "~~/shaders/Anime4K_Clamp_Highlights.glsl:~~/shaders/Anime4K_Restore_CNN_VL.glsl:~~/shaders/Anime4K_Upscale_CNN_x2_VL.glsl:~~/shaders/Anime4K_AutoDownscalePre_x2.glsl:~~/shaders/Anime4K_AutoDownscalePre_x4.glsl:~~/shaders/Anime4K_Upscale_CNN_x2_M.glsl"; show-text "Anime4K: Mode A (HQ)"
CTRL+2 no-osd change-list glsl-shaders set "~~/shaders/Anime4K_Clamp_Highlights.glsl:~~/shaders/Anime4K_Restore_CNN_Soft_VL.glsl:~~/shaders/Anime4K_Upscale_CNN_x2_VL.glsl:~~/shaders/Anime4K_AutoDownscalePre_x2.glsl:~~/shaders/Anime4K_AutoDownscalePre_x4.glsl:~~/shaders/Anime4K_Upscale_CNN_x2_M.glsl"; show-text "Anime4K: Mode B (HQ)"
CTRL+3 no-osd change-list glsl-shaders set "~~/shaders/Anime4K_Clamp_Highlights.glsl:~~/shaders/Anime4K_Upscale_Denoise_CNN_x2_VL.glsl:~~/shaders/Anime4K_AutoDownscalePre_x2.glsl:~~/shaders/Anime4K_AutoDownscalePre_x4.glsl:~~/shaders/Anime4K_Upscale_CNN_x2_M.glsl"; show-text "Anime4K: Mode C (HQ)"
CTRL+4 no-osd change-list glsl-shaders set "~~/shaders/Anime4K_Clamp_Highlights.glsl:~~/shaders/Anime4K_Restore_CNN_VL.glsl:~~/shaders/Anime4K_Upscale_CNN_x2_VL.glsl:~~/shaders/Anime4K_Restore_CNN_M.glsl:~~/shaders/Anime4K_AutoDownscalePre_x2.glsl:~~/shaders/Anime4K_AutoDownscalePre_x4.glsl:~~/shaders/Anime4K_Upscale_CNN_x2_M.glsl"; show-text "Anime4K: Mode A+A (HQ)"
CTRL+5 no-osd change-list glsl-shaders set "~~/shaders/Anime4K_Clamp_Highlights.glsl:~~/shaders/Anime4K_Restore_CNN_Soft_VL.glsl:~~/shaders/Anime4K_Upscale_CNN_x2_VL.glsl:~~/shaders/Anime4K_AutoDownscalePre_x2.glsl:~~/shaders/Anime4K_AutoDownscalePre_x4.glsl:~~/shaders/Anime4K_Restore_CNN_Soft_M.glsl:~~/shaders/Anime4K_Upscale_CNN_x2_M.glsl"; show-text "Anime4K: Mode B+B (HQ)"
CTRL+6 no-osd change-list glsl-shaders set "~~/shaders/Anime4K_Clamp_Highlights.glsl:~~/shaders/Anime4K_Upscale_Denoise_CNN_x2_VL.glsl:~~/shaders/Anime4K_AutoDownscalePre_x2.glsl:~~/shaders/Anime4K_AutoDownscalePre_x4.glsl:~~/shaders/Anime4K_Restore_CNN_M.glsl:~~/shaders/Anime4K_Upscale_CNN_x2_M.glsl"; show-text "Anime4K: Mode C+A (HQ)"
CTRL+0 no-osd change-list glsl-shaders clr ""; show-text "GLSL shaders cleared"

View file

@ -0,0 +1,93 @@
##
## MPlayer-style key bindings
##
## Save it as ~/.config/mpv/input.conf to use it.
##
## Generally, it's recommended to use this as reference-only.
##
RIGHT seek +10
LEFT seek -10
DOWN seek -60
UP seek +60
PGUP seek 600
PGDWN seek -600
m cycle mute
SHARP cycle audio # switch audio streams
+ add audio-delay 0.100
= add audio-delay 0.100
- add audio-delay -0.100
[ multiply speed 0.9091 # scale playback speed
] multiply speed 1.1
{ multiply speed 0.5
} multiply speed 2.0
BS set speed 1.0 # reset speed to normal
q quit
ESC quit
ENTER playlist-next force # skip to next file
p cycle pause
. frame-step # advance one frame and pause
SPACE cycle pause
HOME set playlist-pos 0 # not the same as MPlayer
#END pt_up_step -1
> playlist-next # skip to next file
< playlist-prev # previous
#INS alt_src_step 1
#DEL alt_src_step -1
o osd
I show-text "${filename}" # display filename in osd
P show-progress
z add sub-delay -0.1 # subtract 100 ms delay from subs
x add sub-delay +0.1 # add
9 add volume -1
/ add volume -1
0 add volume 1
* add volume 1
1 add contrast -1
2 add contrast 1
3 add brightness -1
4 add brightness 1
5 add hue -1
6 add hue 1
7 add saturation -1
8 add saturation 1
( add balance -0.1 # adjust audio balance in favor of left
) add balance +0.1 # right
d cycle framedrop
D cycle deinterlace # toggle deinterlacer (auto-inserted filter)
r add sub-pos -1 # move subtitles up
t add sub-pos +1 # down
#? sub-step +1 # immediately display next subtitle
#? sub-step -1 # previous
#? add sub-scale +0.1 # increase subtitle font size
#? add sub-scale -0.1 # decrease subtitle font size
f cycle fullscreen
T cycle ontop # toggle video window ontop of other windows
w add panscan -0.1 # zoom out with -panscan 0 -fs
e add panscan +0.1 # in
c cycle stream-capture # save (and append) file/stream to stream.dump with -capture
s screenshot # take a screenshot (if you want PNG, use "--screenshot-format=png")
S screenshot - each-frame # S will take a png screenshot of every frame
h cycle tv-channel 1
l cycle tv-channel -1
n cycle tv-norm
#b tv_step_chanlist
#? add chapter -1 # skip to previous dvd chapter
#? add chapter +1 # next
##
## Advanced seek
## Uncomment the following lines to be able to seek to n% of the media with
## the Fx keys.
##
#F1 seek 10 absolute-percent
#F2 seek 20 absolute-percent
#F3 seek 30 absolute-percent
#F4 seek 40 absolute-percent
#F5 seek 50 absolute-percent
#F6 seek 60 absolute-percent
#F7 seek 70 absolute-percent
#F8 seek 80 absolute-percent
#F9 seek 90 absolute-percent

155
config/mpv/mpv.conf Normal file
View file

@ -0,0 +1,155 @@
#
# Example mpv configuration file
#
# Warning:
#
# The commented example options usually do _not_ set the default values. Call
# mpv with --list-options to see the default values for most options. There is
# no builtin or example mpv.conf with all the defaults.
#
#
# Configuration files are read system-wide from /usr/local/etc/mpv.conf
# and per-user from ~/.config/mpv/mpv.conf, where per-user settings override
# system-wide settings, all of which are overridden by the command line.
#
# Configuration file settings and the command line options use the same
# underlying mechanisms. Most options can be put into the configuration file
# by dropping the preceding '--'. See the man page for a complete list of
# options.
#
# Lines starting with '#' are comments and are ignored.
#
# See the CONFIGURATION FILES section in the man page
# for a detailed description of the syntax.
#
# Profiles should be placed at the bottom of the configuration file to ensure
# that settings wanted as defaults are not restricted to specific profiles.
##################
# video settings #
##################
# Start in fullscreen mode by default.
#fs=yes
# force starting with centered window
#geometry=50%:50%
# don't allow a new window to have a size larger than 90% of the screen size
#autofit-larger=90%x90%
# Do not close the window on exit.
#keep-open=yes
# Do not wait with showing the video window until it has loaded. (This will
# resize the window once video is loaded. Also always shows a window with
# audio.)
#force-window=immediate
# Disable the On Screen Controller (OSC).
osc=no
# Keep the player window on top of all other windows.
#ontop=yes
# Specify high quality video rendering preset (for --vo=gpu only)
# Can cause performance problems with some drivers and GPUs.
profile=gpu-hq
# scale=ewa_lanczossharp
# cscale=ewa_lanczossharp
# Force video to lock on the display's refresh rate, and change video and audio
# speed to some degree to ensure synchronous playback - can cause problems
# with some drivers and desktop environments.
# video-sync=display-resample
# interpolation
# tscale=oversample
# Enable hardware decoding if available. Often, this does not work with all
# video outputs, but should work well with default settings on most systems.
# If performance or energy usage is an issue, forcing the vdpau or vaapi VOs
# may or may not help.
#hwdec=auto
##################
# audio settings #
##################
# Specify default audio device. You can list devices with: --audio-device=help
# The option takes the device string (the stuff between the '...').
#audio-device=alsa/default
# Do not filter audio to keep pitch when changing playback speed.
#audio-pitch-correction=no
# Output 5.1 audio natively, and upmix/downmix audio with a different format.
#audio-channels=5.1
# Disable any automatic remix, _if_ the audio output accepts the audio format.
# of the currently played file. See caveats mentioned in the manpage.
# (The default is "auto-safe", see manpage.)
#audio-channels=auto
##################
# other settings #
##################
# Pretend to be a web browser. Might fix playback with some streaming sites,
# but also will break with shoutcast streams.
#user-agent="Mozilla/5.0"
# cache settings
#
# Use a large seekable RAM cache even for local input.
#cache=yes
#
# Use extra large RAM cache (needs cache=yes to make it useful).
#demuxer-max-bytes=500M
#demuxer-max-back-bytes=100M
#
# Disable the behavior that the player will pause if the cache goes below a
# certain fill size.
#cache-pause=no
#
# Store cache payload on the hard disk instead of in RAM. (This may negatively
# impact performance unless used for slow input such as network.)
#cache-dir=~/.cache/
#cache-on-disk=yes
# Display English subtitles if available.
#slang=en
# Play Finnish audio if available, fall back to English otherwise.
#alang=fi,en
# Change subtitle encoding. For Arabic subtitles use 'cp1256'.
# If the file seems to be valid UTF-8, prefer UTF-8.
# (You can add '+' in front of the codepage to force it.)
#sub-codepage=cp1256
# You can also include other configuration files.
#include=/path/to/the/file/you/want/to/include
############
# Profiles #
############
# The options declared as part of profiles override global default settings,
# but only take effect when the profile is active.
# The following profile can be enabled on the command line with: --profile=eye-cancer
#[eye-cancer]
#sharpen=5
[twitch]
profile-cond=get("path", ""):find("^https://www.twitch.tv/") ~= nil
profile-restore=copy-equal
sub-font-size=30
sub-align-x=right
sub-align-y=top
[music-stream]
force-window=yes
ytdl-format=bestvideo[height<=?720][fps<=?30][vcodec!=?vp9]+bestaudio/best
window-maximized=yes

View file

@ -0,0 +1,61 @@
# This file contains all bindings that were removed after a certain release.
# If you want MPlayer bindings, use mplayer-input.conf
# Pick the bindings you want back and add them to your own input.conf. Append
# this file to your input.conf if you want them all back:
#
# cat restore-old-bindings.conf >> ~/.config/mpv/input.conf
#
# Older installations use ~/.mpv/input.conf instead.
# changed in mpv 0.27.0 (macOS and Wayland only)
# WHEEL_UP seek 10
# WHEEL_DOWN seek -10
# WHEEL_LEFT seek 5
# WHEEL_RIGHT seek -5
# changed in mpv 0.26.0
h cycle tv-channel -1 # previous channel
k cycle tv-channel +1 # next channel
H cycle dvb-channel-name -1 # previous channel
K cycle dvb-channel-name +1 # next channel
I show-text "${filename}" # display filename in osd
# changed in mpv 0.24.0
L cycle-values loop "inf" "no"
# changed in mpv 0.10.0
O osd
D cycle deinterlace
d cycle framedrop
# changed in mpv 0.7.0
ENTER playlist-next force
# changed in mpv 0.6.0
ESC quit
# changed in mpv 0.5.0
PGUP seek 600
PGDWN seek -600
RIGHT seek 10
LEFT seek -10
+ add audio-delay 0.100
- add audio-delay -0.100
( add balance -0.1
) add balance 0.1
F cycle sub-forced-only
TAB cycle program
A cycle angle
U stop
o osd
I show-text "${filename}"

View file

@ -0,0 +1,70 @@
# The thumbnail cache directory.
# On Windows this defaults to %TEMP%\mpv_thumbs_cache,
# and on other platforms to /tmp/mpv_thumbs_cache.
# The directory will be created automatically, but must be writeable!
# Use absolute paths, and take note that environment variables like %TEMP% are unsupported (despite the default)!
cache_directory=/tmp/my_mpv_thumbnails
# THIS IS NOT A WINDOWS PATH. COMMENT IT OUT OR ADJUST IT YOURSELF.
# Whether to generate thumbnails automatically on video load, without a keypress
# Defaults to yes
autogenerate=yes
# Only automatically thumbnail videos shorter than this (in seconds)
# You will have to press T (or your own keybind) to enable the thumbnail previews
# Set to 0 to disable the check, ie. thumbnail videos no matter how long they are
# Defaults to 3600 (one hour)
# autogenerate_max_duration=3600
# Use mpv to generate thumbnail even if ffmpeg is found in PATH
# ffmpeg is slightly faster than mpv but lacks support for ordered chapters in MKVs,
# which can break the resulting thumbnails. You have been warned.
# Defaults to yes (don't use ffmpeg)
# prefer_mpv=[yes/no]
# Explicitly disable subtitles on the mpv sub-calls
# mpv can and will by default render subtitles into the thumbnails.
# If this is not what you wish, set mpv_no_sub to yes
# Defaults to no
# mpv_no_sub=[yes/no]
# Enable to disable the built-in keybind ("T") to add your own, see after the block
# disable_keybinds=[yes/no]
# The maximum dimensions of the thumbnails, in pixels
# Defaults to 200 and 200
# thumbnail_width=200
# thumbnail_height=200
# The thumbnail count target
# (This will result in a thumbnail every ~10 seconds for a 25 minute video)
# thumbnail_count=150
# The above target count will be adjusted by the minimum and
# maximum time difference between thumbnails.
# The thumbnail_count will be used to calculate a target separation,
# and min/max_delta will be used to constrict it.
# In other words, thumbnails will be:
# - at least min_delta seconds apart (limiting the amount)
# - at most max_delta seconds apart (raising the amount if needed)
# Defaults to 5 and 90, values are seconds
# min_delta=5
# max_delta=90
# 120 seconds aka 2 minutes will add more thumbnails only when the video is over 5 hours long!
# Below are overrides for remote urls (you generally want less thumbnails, because it's slow!)
# Thumbnailing network paths will be done with mpv (leveraging youtube-dl)
# Allow thumbnailing network paths (naive check for "://")
# Defaults to no
# thumbnail_network=[yes/no]
# Override thumbnail count, min/max delta, as above
# remote_thumbnail_count=60
# remote_min_delta=15
# remote_max_delta=120
# Try to grab the raw stream and disable ytdl for the mpv subcalls
# Much faster than passing the url to ytdl again, but may cause problems with some sites
# Defaults to yes
# remote_direct_stream=[yes/no]

View file

@ -0,0 +1,19 @@
local utils = require 'mp.utils'
local pid = utils.getpid()
local function center_floating_mpv()
mpv_window_id = io.popen("xdotool search --pid " .. pid):read()
-- mpv can have a slight delay in launching a window, or be called without one at all
if mpv_window_id == nil then return end
floating = io.popen("xprop -id " .. mpv_window_id):read("*a")
if string.match(floating, "FLOATING") then
os.execute("i3-msg -q '[id=" .. mpv_window_id .. "]' move position center")
end
end
mp.register_event("playback-restart", center_floating_mpv)
-- mpv should still be centered when fullscreen is toggled
mp.observe_property("fullscreen", "bool", center_floating_mpv)

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,736 @@
--[[
Copyright (C) 2017 AMM
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
]]--
--[[
mpv_thumbnail_script.lua 0.4.7 - commit 6282073 (branch master)
https://github.com/TheAMM/mpv_thumbnail_script
Built on 2022-02-05 16:00:24
]]--
local assdraw = require 'mp.assdraw'
local msg = require 'mp.msg'
local opt = require 'mp.options'
local utils = require 'mp.utils'
-- Determine platform --
ON_WINDOWS = (package.config:sub(1,1) ~= '/')
-- Some helper functions needed to parse the options --
function isempty(v) return (v == false) or (v == nil) or (v == "") or (v == 0) or (type(v) == "table" and next(v) == nil) end
function divmod (a, b)
return math.floor(a / b), a % b
end
-- Better modulo
function bmod( i, N )
return (i % N + N) % N
end
function join_paths(...)
local sep = ON_WINDOWS and "\\" or "/"
local result = "";
for i, p in pairs({...}) do
if p ~= "" then
if is_absolute_path(p) then
result = p
else
result = (result ~= "") and (result:gsub("[\\"..sep.."]*$", "") .. sep .. p) or p
end
end
end
return result:gsub("[\\"..sep.."]*$", "")
end
-- /some/path/file.ext -> /some/path, file.ext
function split_path( path )
local sep = ON_WINDOWS and "\\" or "/"
local first_index, last_index = path:find('^.*' .. sep)
if last_index == nil then
return "", path
else
local dir = path:sub(0, last_index-1)
local file = path:sub(last_index+1, -1)
return dir, file
end
end
function is_absolute_path( path )
local tmp, is_win = path:gsub("^[A-Z]:\\", "")
local tmp, is_unix = path:gsub("^/", "")
return (is_win > 0) or (is_unix > 0)
end
function Set(source)
local set = {}
for _, l in ipairs(source) do set[l] = true end
return set
end
---------------------------
-- More helper functions --
---------------------------
-- Removes all keys from a table, without destroying the reference to it
function clear_table(target)
for key, value in pairs(target) do
target[key] = nil
end
end
function shallow_copy(target)
local copy = {}
for k, v in pairs(target) do
copy[k] = v
end
return copy
end
-- Rounds to given decimals. eg. round_dec(3.145, 0) => 3
function round_dec(num, idp)
local mult = 10^(idp or 0)
return math.floor(num * mult + 0.5) / mult
end
function file_exists(name)
local f = io.open(name, "rb")
if f ~= nil then
local ok, err, code = f:read(1)
io.close(f)
return code == nil
else
return false
end
end
function path_exists(name)
local f = io.open(name, "rb")
if f ~= nil then
io.close(f)
return true
else
return false
end
end
function create_directories(path)
local cmd
if ON_WINDOWS then
cmd = { args = {"cmd", "/c", "mkdir", path} }
else
cmd = { args = {"mkdir", "-p", path} }
end
utils.subprocess(cmd)
end
-- Find an executable in PATH or CWD with the given name
function find_executable(name)
local delim = ON_WINDOWS and ";" or ":"
local pwd = os.getenv("PWD") or utils.getcwd()
local path = os.getenv("PATH")
local env_path = pwd .. delim .. path -- Check CWD first
local result, filename
for path_dir in env_path:gmatch("[^"..delim.."]+") do
filename = join_paths(path_dir, name)
if file_exists(filename) then
result = filename
break
end
end
return result
end
local ExecutableFinder = { path_cache = {} }
-- Searches for an executable and caches the result if any
function ExecutableFinder:get_executable_path( name, raw_name )
name = ON_WINDOWS and not raw_name and (name .. ".exe") or name
if self.path_cache[name] == nil then
self.path_cache[name] = find_executable(name) or false
end
return self.path_cache[name]
end
-- Format seconds to HH.MM.SS.sss
function format_time(seconds, sep, decimals)
decimals = decimals == nil and 3 or decimals
sep = sep and sep or "."
local s = seconds
local h, s = divmod(s, 60*60)
local m, s = divmod(s, 60)
local second_format = string.format("%%0%d.%df", 2+(decimals > 0 and decimals+1 or 0), decimals)
return string.format("%02d"..sep.."%02d"..sep..second_format, h, m, s)
end
-- Format seconds to 1h 2m 3.4s
function format_time_hms(seconds, sep, decimals, force_full)
decimals = decimals == nil and 1 or decimals
sep = sep ~= nil and sep or " "
local s = seconds
local h, s = divmod(s, 60*60)
local m, s = divmod(s, 60)
if force_full or h > 0 then
return string.format("%dh"..sep.."%dm"..sep.."%." .. tostring(decimals) .. "fs", h, m, s)
elseif m > 0 then
return string.format("%dm"..sep.."%." .. tostring(decimals) .. "fs", m, s)
else
return string.format("%." .. tostring(decimals) .. "fs", s)
end
end
-- Writes text on OSD and console
function log_info(txt, timeout)
timeout = timeout or 1.5
msg.info(txt)
mp.osd_message(txt, timeout)
end
-- Join table items, ala ({"a", "b", "c"}, "=", "-", ", ") => "=a-, =b-, =c-"
function join_table(source, before, after, sep)
before = before or ""
after = after or ""
sep = sep or ", "
local result = ""
for i, v in pairs(source) do
if not isempty(v) then
local part = before .. v .. after
if i == 1 then
result = part
else
result = result .. sep .. part
end
end
end
return result
end
function wrap(s, char)
char = char or "'"
return char .. s .. char
end
-- Wraps given string into 'string' and escapes any 's in it
function escape_and_wrap(s, char, replacement)
char = char or "'"
replacement = replacement or "\\" .. char
return wrap(string.gsub(s, char, replacement), char)
end
-- Escapes single quotes in a string and wraps the input in single quotes
function escape_single_bash(s)
return escape_and_wrap(s, "'", "'\\''")
end
-- Returns (a .. b) if b is not empty or nil
function joined_or_nil(a, b)
return not isempty(b) and (a .. b) or nil
end
-- Put items from one table into another
function extend_table(target, source)
for i, v in pairs(source) do
table.insert(target, v)
end
end
-- Creates a handle and filename for a temporary random file (in current directory)
function create_temporary_file(base, mode, suffix)
local handle, filename
suffix = suffix or ""
while true do
filename = base .. tostring(math.random(1, 5000)) .. suffix
handle = io.open(filename, "r")
if not handle then
handle = io.open(filename, mode)
break
end
io.close(handle)
end
return handle, filename
end
function get_processor_count()
local proc_count
if ON_WINDOWS then
proc_count = tonumber(os.getenv("NUMBER_OF_PROCESSORS"))
else
local cpuinfo_handle = io.open("/proc/cpuinfo")
if cpuinfo_handle ~= nil then
local cpuinfo_contents = cpuinfo_handle:read("*a")
local _, replace_count = cpuinfo_contents:gsub('processor', '')
proc_count = replace_count
end
end
if proc_count and proc_count > 0 then
return proc_count
else
return nil
end
end
function substitute_values(string, values)
local substitutor = function(match)
if match == "%" then
return "%"
else
-- nil is discarded by gsub
return values[match]
end
end
local substituted = string:gsub('%%(.)', substitutor)
return substituted
end
-- ASS HELPERS --
function round_rect_top( ass, x0, y0, x1, y1, r )
local c = 0.551915024494 * r -- circle approximation
ass:move_to(x0 + r, y0)
ass:line_to(x1 - r, y0) -- top line
if r > 0 then
ass:bezier_curve(x1 - r + c, y0, x1, y0 + r - c, x1, y0 + r) -- top right corner
end
ass:line_to(x1, y1) -- right line
ass:line_to(x0, y1) -- bottom line
ass:line_to(x0, y0 + r) -- left line
if r > 0 then
ass:bezier_curve(x0, y0 + r - c, x0 + r - c, y0, x0 + r, y0) -- top left corner
end
end
function round_rect(ass, x0, y0, x1, y1, rtl, rtr, rbr, rbl)
local c = 0.551915024494
ass:move_to(x0 + rtl, y0)
ass:line_to(x1 - rtr, y0) -- top line
if rtr > 0 then
ass:bezier_curve(x1 - rtr + rtr*c, y0, x1, y0 + rtr - rtr*c, x1, y0 + rtr) -- top right corner
end
ass:line_to(x1, y1 - rbr) -- right line
if rbr > 0 then
ass:bezier_curve(x1, y1 - rbr + rbr*c, x1 - rbr + rbr*c, y1, x1 - rbr, y1) -- bottom right corner
end
ass:line_to(x0 + rbl, y1) -- bottom line
if rbl > 0 then
ass:bezier_curve(x0 + rbl - rbl*c, y1, x0, y1 - rbl + rbl*c, x0, y1 - rbl) -- bottom left corner
end
ass:line_to(x0, y0 + rtl) -- left line
if rtl > 0 then
ass:bezier_curve(x0, y0 + rtl - rtl*c, x0 + rtl - rtl*c, y0, x0 + rtl, y0) -- top left corner
end
end
local SCRIPT_NAME = "mpv_thumbnail_script"
local default_cache_base = ON_WINDOWS and os.getenv("TEMP") or "/tmp/"
local thumbnailer_options = {
-- The thumbnail directory
cache_directory = join_paths(default_cache_base, "mpv_thumbs_cache"),
------------------------
-- Generation options --
------------------------
-- Automatically generate the thumbnails on video load, without a keypress
autogenerate = true,
-- Only automatically thumbnail videos shorter than this (seconds)
autogenerate_max_duration = 3600, -- 1 hour
-- SHA1-sum filenames over this length
-- It's nice to know what files the thumbnails are (hence directory names)
-- but long URLs may approach filesystem limits.
hash_filename_length = 128,
-- Use mpv to generate thumbnail even if ffmpeg is found in PATH
-- ffmpeg does not handle ordered chapters (MKVs which rely on other MKVs)!
-- mpv is a bit slower, but has better support overall (eg. subtitles in the previews)
prefer_mpv = true,
-- Explicitly disable subtitles on the mpv sub-calls
mpv_no_sub = false,
-- Add a "--no-config" to the mpv sub-call arguments
mpv_no_config = false,
-- Add a "--profile=<mpv_profile>" to the mpv sub-call arguments
-- Use "" to disable
mpv_profile = "",
-- Output debug logs to <thumbnail_path>.log, ala <cache_directory>/<video_filename>/000000.bgra.log
-- The logs are removed after successful encodes, unless you set mpv_keep_logs below
mpv_logs = true,
-- Keep all mpv logs, even the succesfull ones
mpv_keep_logs = false,
-- Disable the built-in keybind ("T") to add your own
disable_keybinds = false,
---------------------
-- Display options --
---------------------
-- Move the thumbnail up or down
-- For example:
-- topbar/bottombar: 24
-- rest: 0
vertical_offset = 24,
-- Adjust background padding
-- Examples:
-- topbar: 0, 10, 10, 10
-- bottombar: 10, 0, 10, 10
-- slimbox/box: 10, 10, 10, 10
pad_top = 10,
pad_bot = 0,
pad_left = 10,
pad_right = 10,
-- If true, pad values are screen-pixels. If false, video-pixels.
pad_in_screenspace = true,
-- Calculate pad into the offset
offset_by_pad = true,
-- Background color in BBGGRR
background_color = "000000",
-- Alpha: 0 - fully opaque, 255 - transparent
background_alpha = 80,
-- Keep thumbnail on the screen near left or right side
constrain_to_screen = true,
-- Do not display the thumbnailing progress
hide_progress = false,
-----------------------
-- Thumbnail options --
-----------------------
-- The maximum dimensions of the thumbnails (pixels)
thumbnail_width = 200,
thumbnail_height = 200,
-- The thumbnail count target
-- (This will result in a thumbnail every ~10 seconds for a 25 minute video)
thumbnail_count = 150,
-- The above target count will be adjusted by the minimum and
-- maximum time difference between thumbnails.
-- The thumbnail_count will be used to calculate a target separation,
-- and min/max_delta will be used to constrict it.
-- In other words, thumbnails will be:
-- at least min_delta seconds apart (limiting the amount)
-- at most max_delta seconds apart (raising the amount if needed)
min_delta = 5,
-- 120 seconds aka 2 minutes will add more thumbnails when the video is over 5 hours!
max_delta = 90,
-- Overrides for remote urls (you generally want less thumbnails!)
-- Thumbnailing network paths will be done with mpv
-- Allow thumbnailing network paths (naive check for "://")
thumbnail_network = false,
-- Override thumbnail count, min/max delta
remote_thumbnail_count = 60,
remote_min_delta = 15,
remote_max_delta = 120,
-- Try to grab the raw stream and disable ytdl for the mpv subcalls
-- Much faster than passing the url to ytdl again, but may cause problems with some sites
remote_direct_stream = true,
}
read_options(thumbnailer_options, SCRIPT_NAME)
function skip_nil(tbl)
local n = {}
for k, v in pairs(tbl) do
table.insert(n, v)
end
return n
end
function create_thumbnail_mpv(file_path, timestamp, size, output_path, options)
options = options or {}
local ytdl_disabled = not options.enable_ytdl and (mp.get_property_native("ytdl") == false
or thumbnailer_options.remote_direct_stream)
local header_fields_arg = nil
local header_fields = mp.get_property_native("http-header-fields")
if #header_fields > 0 then
-- We can't escape the headers, mpv won't parse "--http-header-fields='Name: value'" properly
header_fields_arg = "--http-header-fields=" .. table.concat(header_fields, ",")
end
local profile_arg = nil
if thumbnailer_options.mpv_profile ~= "" then
profile_arg = "--profile=" .. thumbnailer_options.mpv_profile
end
local log_arg = "--log-file=" .. output_path .. ".log"
local mpv_command = skip_nil({
"mpv",
-- Hide console output
"--msg-level=all=no",
-- Disable ytdl
(ytdl_disabled and "--no-ytdl" or nil),
-- Pass HTTP headers from current instance
header_fields_arg,
-- Pass User-Agent and Referer - should do no harm even with ytdl active
"--user-agent=" .. mp.get_property_native("user-agent"),
"--referrer=" .. mp.get_property_native("referrer"),
-- Disable hardware decoding
"--hwdec=no",
-- Insert --no-config, --profile=... and --log-file if enabled
(thumbnailer_options.mpv_no_config and "--no-config" or nil),
profile_arg,
(thumbnailer_options.mpv_logs and log_arg or nil),
file_path,
"--start=" .. tostring(timestamp),
"--frames=1",
"--hr-seek=yes",
"--no-audio",
-- Optionally disable subtitles
(thumbnailer_options.mpv_no_sub and "--no-sub" or nil),
("--vf=scale=%d:%d"):format(size.w, size.h),
"--vf-add=format=bgra",
"--of=rawvideo",
"--ovc=rawvideo",
("--o=%s"):format(output_path)
})
return utils.subprocess({args=mpv_command})
end
function create_thumbnail_ffmpeg(file_path, timestamp, size, output_path)
local ffmpeg_command = {
"ffmpeg",
"-loglevel", "quiet",
"-noaccurate_seek",
"-ss", format_time(timestamp, ":"),
"-i", file_path,
"-frames:v", "1",
"-an",
"-vf", ("scale=%d:%d"):format(size.w, size.h),
"-c:v", "rawvideo",
"-pix_fmt", "bgra",
"-f", "rawvideo",
"-y", output_path
}
return utils.subprocess({args=ffmpeg_command})
end
function check_output(ret, output_path, is_mpv)
local log_path = output_path .. ".log"
local success = true
if ret.killed_by_us then
return nil
else
if ret.error or ret.status ~= 0 then
msg.error("Thumbnailing command failed!")
msg.error("mpv process error:", ret.error)
msg.error("Process stdout:", ret.stdout)
if is_mpv then
msg.error("Debug log:", log_path)
end
success = false
end
if not file_exists(output_path) then
msg.error("Output file missing!", output_path)
success = false
end
end
if is_mpv and not thumbnailer_options.mpv_keep_logs then
-- Remove successful debug logs
if success and file_exists(log_path) then
os.remove(log_path)
end
end
return success
end
function do_worker_job(state_json_string, frames_json_string)
msg.debug("Handling given job")
local thumb_state, err = utils.parse_json(state_json_string)
if err then
msg.error("Failed to parse state JSON")
return
end
local thumbnail_indexes, err = utils.parse_json(frames_json_string)
if err then
msg.error("Failed to parse thumbnail frame indexes")
return
end
local thumbnail_func = create_thumbnail_mpv
if not thumbnailer_options.prefer_mpv then
if ExecutableFinder:get_executable_path("ffmpeg") then
thumbnail_func = create_thumbnail_ffmpeg
else
msg.warn("Could not find ffmpeg in PATH! Falling back on mpv.")
end
end
local file_duration = mp.get_property_native("duration")
local file_path = thumb_state.worker_input_path
if thumb_state.is_remote then
if (thumbnail_func == create_thumbnail_ffmpeg) then
msg.warn("Thumbnailing remote path, falling back on mpv.")
end
thumbnail_func = create_thumbnail_mpv
end
local generate_thumbnail_for_index = function(thumbnail_index)
-- Given a 1-based thumbnail index, generate a thumbnail for it based on the thumbnailer state
local thumb_idx = thumbnail_index - 1
msg.debug("Starting work on thumbnail", thumb_idx)
local thumbnail_path = thumb_state.thumbnail_template:format(thumb_idx)
-- Grab the "middle" of the thumbnail duration instead of the very start, and leave some margin in the end
local timestamp = math.min(file_duration - 0.25, (thumb_idx + 0.5) * thumb_state.thumbnail_delta)
mp.commandv("script-message", "mpv_thumbnail_script-progress", tostring(thumbnail_index))
-- The expected size (raw BGRA image)
local thumbnail_raw_size = (thumb_state.thumbnail_size.w * thumb_state.thumbnail_size.h * 4)
local need_thumbnail_generation = false
-- Check if the thumbnail already exists and is the correct size
local thumbnail_file = io.open(thumbnail_path, "rb")
if thumbnail_file == nil then
need_thumbnail_generation = true
else
local existing_thumbnail_filesize = thumbnail_file:seek("end")
if existing_thumbnail_filesize ~= thumbnail_raw_size then
-- Size doesn't match, so (re)generate
msg.warn("Thumbnail", thumb_idx, "did not match expected size, regenerating")
need_thumbnail_generation = true
end
thumbnail_file:close()
end
if need_thumbnail_generation then
local ret = thumbnail_func(file_path, timestamp, thumb_state.thumbnail_size, thumbnail_path, thumb_state.worker_extra)
local success = check_output(ret, thumbnail_path, thumbnail_func == create_thumbnail_mpv)
if success == nil then
-- Killed by us, changing files, ignore
msg.debug("Changing files, subprocess killed")
return true
elseif not success then
-- Real failure
mp.osd_message("Thumbnailing failed, check console for details", 3.5)
return true
end
else
msg.debug("Thumbnail", thumb_idx, "already done!")
end
-- Verify thumbnail size
-- Sometimes ffmpeg will output an empty file when seeking to a "bad" section (usually the end)
thumbnail_file = io.open(thumbnail_path, "rb")
-- Bail if we can't read the file (it should really exist by now, we checked this in check_output!)
if thumbnail_file == nil then
msg.error("Thumbnail suddenly disappeared!")
return true
end
-- Check the size of the generated file
local thumbnail_file_size = thumbnail_file:seek("end")
thumbnail_file:close()
-- Check if the file is big enough
local missing_bytes = math.max(0, thumbnail_raw_size - thumbnail_file_size)
if missing_bytes > 0 then
msg.warn(("Thumbnail missing %d bytes (expected %d, had %d), padding %s"):format(
missing_bytes, thumbnail_raw_size, thumbnail_file_size, thumbnail_path
))
-- Pad the file if it's missing content (eg. ffmpeg seek to file end)
thumbnail_file = io.open(thumbnail_path, "ab")
thumbnail_file:write(string.rep(string.char(0), missing_bytes))
thumbnail_file:close()
end
msg.debug("Finished work on thumbnail", thumb_idx)
mp.commandv("script-message", "mpv_thumbnail_script-ready", tostring(thumbnail_index), thumbnail_path)
end
msg.debug(("Generating %d thumbnails @ %dx%d for %q"):format(
#thumbnail_indexes,
thumb_state.thumbnail_size.w,
thumb_state.thumbnail_size.h,
file_path))
for i, thumbnail_index in ipairs(thumbnail_indexes) do
local bail = generate_thumbnail_for_index(thumbnail_index)
if bail then return end
end
end
-- Set up listeners and keybinds
-- Job listener
mp.register_script_message("mpv_thumbnail_script-job", do_worker_job)
-- Register this worker with the master script
local register_timer = nil
local register_timeout = mp.get_time() + 1.5
local register_function = function()
if mp.get_time() > register_timeout and register_timer then
msg.error("Thumbnail worker registering timed out")
register_timer:stop()
else
msg.debug("Announcing self to master...")
mp.commandv("script-message", "mpv_thumbnail_script-worker", mp.get_script_name())
end
end
register_timer = mp.add_periodic_timer(0.1, register_function)
mp.register_script_message("mpv_thumbnail_script-slaved", function()
msg.debug("Successfully registered with master")
register_timer:stop()
end)

View file

@ -0,0 +1,736 @@
--[[
Copyright (C) 2017 AMM
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
]]--
--[[
mpv_thumbnail_script.lua 0.4.7 - commit 6282073 (branch master)
https://github.com/TheAMM/mpv_thumbnail_script
Built on 2022-02-05 16:00:24
]]--
local assdraw = require 'mp.assdraw'
local msg = require 'mp.msg'
local opt = require 'mp.options'
local utils = require 'mp.utils'
-- Determine platform --
ON_WINDOWS = (package.config:sub(1,1) ~= '/')
-- Some helper functions needed to parse the options --
function isempty(v) return (v == false) or (v == nil) or (v == "") or (v == 0) or (type(v) == "table" and next(v) == nil) end
function divmod (a, b)
return math.floor(a / b), a % b
end
-- Better modulo
function bmod( i, N )
return (i % N + N) % N
end
function join_paths(...)
local sep = ON_WINDOWS and "\\" or "/"
local result = "";
for i, p in pairs({...}) do
if p ~= "" then
if is_absolute_path(p) then
result = p
else
result = (result ~= "") and (result:gsub("[\\"..sep.."]*$", "") .. sep .. p) or p
end
end
end
return result:gsub("[\\"..sep.."]*$", "")
end
-- /some/path/file.ext -> /some/path, file.ext
function split_path( path )
local sep = ON_WINDOWS and "\\" or "/"
local first_index, last_index = path:find('^.*' .. sep)
if last_index == nil then
return "", path
else
local dir = path:sub(0, last_index-1)
local file = path:sub(last_index+1, -1)
return dir, file
end
end
function is_absolute_path( path )
local tmp, is_win = path:gsub("^[A-Z]:\\", "")
local tmp, is_unix = path:gsub("^/", "")
return (is_win > 0) or (is_unix > 0)
end
function Set(source)
local set = {}
for _, l in ipairs(source) do set[l] = true end
return set
end
---------------------------
-- More helper functions --
---------------------------
-- Removes all keys from a table, without destroying the reference to it
function clear_table(target)
for key, value in pairs(target) do
target[key] = nil
end
end
function shallow_copy(target)
local copy = {}
for k, v in pairs(target) do
copy[k] = v
end
return copy
end
-- Rounds to given decimals. eg. round_dec(3.145, 0) => 3
function round_dec(num, idp)
local mult = 10^(idp or 0)
return math.floor(num * mult + 0.5) / mult
end
function file_exists(name)
local f = io.open(name, "rb")
if f ~= nil then
local ok, err, code = f:read(1)
io.close(f)
return code == nil
else
return false
end
end
function path_exists(name)
local f = io.open(name, "rb")
if f ~= nil then
io.close(f)
return true
else
return false
end
end
function create_directories(path)
local cmd
if ON_WINDOWS then
cmd = { args = {"cmd", "/c", "mkdir", path} }
else
cmd = { args = {"mkdir", "-p", path} }
end
utils.subprocess(cmd)
end
-- Find an executable in PATH or CWD with the given name
function find_executable(name)
local delim = ON_WINDOWS and ";" or ":"
local pwd = os.getenv("PWD") or utils.getcwd()
local path = os.getenv("PATH")
local env_path = pwd .. delim .. path -- Check CWD first
local result, filename
for path_dir in env_path:gmatch("[^"..delim.."]+") do
filename = join_paths(path_dir, name)
if file_exists(filename) then
result = filename
break
end
end
return result
end
local ExecutableFinder = { path_cache = {} }
-- Searches for an executable and caches the result if any
function ExecutableFinder:get_executable_path( name, raw_name )
name = ON_WINDOWS and not raw_name and (name .. ".exe") or name
if self.path_cache[name] == nil then
self.path_cache[name] = find_executable(name) or false
end
return self.path_cache[name]
end
-- Format seconds to HH.MM.SS.sss
function format_time(seconds, sep, decimals)
decimals = decimals == nil and 3 or decimals
sep = sep and sep or "."
local s = seconds
local h, s = divmod(s, 60*60)
local m, s = divmod(s, 60)
local second_format = string.format("%%0%d.%df", 2+(decimals > 0 and decimals+1 or 0), decimals)
return string.format("%02d"..sep.."%02d"..sep..second_format, h, m, s)
end
-- Format seconds to 1h 2m 3.4s
function format_time_hms(seconds, sep, decimals, force_full)
decimals = decimals == nil and 1 or decimals
sep = sep ~= nil and sep or " "
local s = seconds
local h, s = divmod(s, 60*60)
local m, s = divmod(s, 60)
if force_full or h > 0 then
return string.format("%dh"..sep.."%dm"..sep.."%." .. tostring(decimals) .. "fs", h, m, s)
elseif m > 0 then
return string.format("%dm"..sep.."%." .. tostring(decimals) .. "fs", m, s)
else
return string.format("%." .. tostring(decimals) .. "fs", s)
end
end
-- Writes text on OSD and console
function log_info(txt, timeout)
timeout = timeout or 1.5
msg.info(txt)
mp.osd_message(txt, timeout)
end
-- Join table items, ala ({"a", "b", "c"}, "=", "-", ", ") => "=a-, =b-, =c-"
function join_table(source, before, after, sep)
before = before or ""
after = after or ""
sep = sep or ", "
local result = ""
for i, v in pairs(source) do
if not isempty(v) then
local part = before .. v .. after
if i == 1 then
result = part
else
result = result .. sep .. part
end
end
end
return result
end
function wrap(s, char)
char = char or "'"
return char .. s .. char
end
-- Wraps given string into 'string' and escapes any 's in it
function escape_and_wrap(s, char, replacement)
char = char or "'"
replacement = replacement or "\\" .. char
return wrap(string.gsub(s, char, replacement), char)
end
-- Escapes single quotes in a string and wraps the input in single quotes
function escape_single_bash(s)
return escape_and_wrap(s, "'", "'\\''")
end
-- Returns (a .. b) if b is not empty or nil
function joined_or_nil(a, b)
return not isempty(b) and (a .. b) or nil
end
-- Put items from one table into another
function extend_table(target, source)
for i, v in pairs(source) do
table.insert(target, v)
end
end
-- Creates a handle and filename for a temporary random file (in current directory)
function create_temporary_file(base, mode, suffix)
local handle, filename
suffix = suffix or ""
while true do
filename = base .. tostring(math.random(1, 5000)) .. suffix
handle = io.open(filename, "r")
if not handle then
handle = io.open(filename, mode)
break
end
io.close(handle)
end
return handle, filename
end
function get_processor_count()
local proc_count
if ON_WINDOWS then
proc_count = tonumber(os.getenv("NUMBER_OF_PROCESSORS"))
else
local cpuinfo_handle = io.open("/proc/cpuinfo")
if cpuinfo_handle ~= nil then
local cpuinfo_contents = cpuinfo_handle:read("*a")
local _, replace_count = cpuinfo_contents:gsub('processor', '')
proc_count = replace_count
end
end
if proc_count and proc_count > 0 then
return proc_count
else
return nil
end
end
function substitute_values(string, values)
local substitutor = function(match)
if match == "%" then
return "%"
else
-- nil is discarded by gsub
return values[match]
end
end
local substituted = string:gsub('%%(.)', substitutor)
return substituted
end
-- ASS HELPERS --
function round_rect_top( ass, x0, y0, x1, y1, r )
local c = 0.551915024494 * r -- circle approximation
ass:move_to(x0 + r, y0)
ass:line_to(x1 - r, y0) -- top line
if r > 0 then
ass:bezier_curve(x1 - r + c, y0, x1, y0 + r - c, x1, y0 + r) -- top right corner
end
ass:line_to(x1, y1) -- right line
ass:line_to(x0, y1) -- bottom line
ass:line_to(x0, y0 + r) -- left line
if r > 0 then
ass:bezier_curve(x0, y0 + r - c, x0 + r - c, y0, x0 + r, y0) -- top left corner
end
end
function round_rect(ass, x0, y0, x1, y1, rtl, rtr, rbr, rbl)
local c = 0.551915024494
ass:move_to(x0 + rtl, y0)
ass:line_to(x1 - rtr, y0) -- top line
if rtr > 0 then
ass:bezier_curve(x1 - rtr + rtr*c, y0, x1, y0 + rtr - rtr*c, x1, y0 + rtr) -- top right corner
end
ass:line_to(x1, y1 - rbr) -- right line
if rbr > 0 then
ass:bezier_curve(x1, y1 - rbr + rbr*c, x1 - rbr + rbr*c, y1, x1 - rbr, y1) -- bottom right corner
end
ass:line_to(x0 + rbl, y1) -- bottom line
if rbl > 0 then
ass:bezier_curve(x0 + rbl - rbl*c, y1, x0, y1 - rbl + rbl*c, x0, y1 - rbl) -- bottom left corner
end
ass:line_to(x0, y0 + rtl) -- left line
if rtl > 0 then
ass:bezier_curve(x0, y0 + rtl - rtl*c, x0 + rtl - rtl*c, y0, x0 + rtl, y0) -- top left corner
end
end
local SCRIPT_NAME = "mpv_thumbnail_script"
local default_cache_base = ON_WINDOWS and os.getenv("TEMP") or "/tmp/"
local thumbnailer_options = {
-- The thumbnail directory
cache_directory = join_paths(default_cache_base, "mpv_thumbs_cache"),
------------------------
-- Generation options --
------------------------
-- Automatically generate the thumbnails on video load, without a keypress
autogenerate = true,
-- Only automatically thumbnail videos shorter than this (seconds)
autogenerate_max_duration = 3600, -- 1 hour
-- SHA1-sum filenames over this length
-- It's nice to know what files the thumbnails are (hence directory names)
-- but long URLs may approach filesystem limits.
hash_filename_length = 128,
-- Use mpv to generate thumbnail even if ffmpeg is found in PATH
-- ffmpeg does not handle ordered chapters (MKVs which rely on other MKVs)!
-- mpv is a bit slower, but has better support overall (eg. subtitles in the previews)
prefer_mpv = true,
-- Explicitly disable subtitles on the mpv sub-calls
mpv_no_sub = false,
-- Add a "--no-config" to the mpv sub-call arguments
mpv_no_config = false,
-- Add a "--profile=<mpv_profile>" to the mpv sub-call arguments
-- Use "" to disable
mpv_profile = "",
-- Output debug logs to <thumbnail_path>.log, ala <cache_directory>/<video_filename>/000000.bgra.log
-- The logs are removed after successful encodes, unless you set mpv_keep_logs below
mpv_logs = true,
-- Keep all mpv logs, even the succesfull ones
mpv_keep_logs = false,
-- Disable the built-in keybind ("T") to add your own
disable_keybinds = false,
---------------------
-- Display options --
---------------------
-- Move the thumbnail up or down
-- For example:
-- topbar/bottombar: 24
-- rest: 0
vertical_offset = 24,
-- Adjust background padding
-- Examples:
-- topbar: 0, 10, 10, 10
-- bottombar: 10, 0, 10, 10
-- slimbox/box: 10, 10, 10, 10
pad_top = 10,
pad_bot = 0,
pad_left = 10,
pad_right = 10,
-- If true, pad values are screen-pixels. If false, video-pixels.
pad_in_screenspace = true,
-- Calculate pad into the offset
offset_by_pad = true,
-- Background color in BBGGRR
background_color = "000000",
-- Alpha: 0 - fully opaque, 255 - transparent
background_alpha = 80,
-- Keep thumbnail on the screen near left or right side
constrain_to_screen = true,
-- Do not display the thumbnailing progress
hide_progress = false,
-----------------------
-- Thumbnail options --
-----------------------
-- The maximum dimensions of the thumbnails (pixels)
thumbnail_width = 200,
thumbnail_height = 200,
-- The thumbnail count target
-- (This will result in a thumbnail every ~10 seconds for a 25 minute video)
thumbnail_count = 150,
-- The above target count will be adjusted by the minimum and
-- maximum time difference between thumbnails.
-- The thumbnail_count will be used to calculate a target separation,
-- and min/max_delta will be used to constrict it.
-- In other words, thumbnails will be:
-- at least min_delta seconds apart (limiting the amount)
-- at most max_delta seconds apart (raising the amount if needed)
min_delta = 5,
-- 120 seconds aka 2 minutes will add more thumbnails when the video is over 5 hours!
max_delta = 90,
-- Overrides for remote urls (you generally want less thumbnails!)
-- Thumbnailing network paths will be done with mpv
-- Allow thumbnailing network paths (naive check for "://")
thumbnail_network = false,
-- Override thumbnail count, min/max delta
remote_thumbnail_count = 60,
remote_min_delta = 15,
remote_max_delta = 120,
-- Try to grab the raw stream and disable ytdl for the mpv subcalls
-- Much faster than passing the url to ytdl again, but may cause problems with some sites
remote_direct_stream = true,
}
read_options(thumbnailer_options, SCRIPT_NAME)
function skip_nil(tbl)
local n = {}
for k, v in pairs(tbl) do
table.insert(n, v)
end
return n
end
function create_thumbnail_mpv(file_path, timestamp, size, output_path, options)
options = options or {}
local ytdl_disabled = not options.enable_ytdl and (mp.get_property_native("ytdl") == false
or thumbnailer_options.remote_direct_stream)
local header_fields_arg = nil
local header_fields = mp.get_property_native("http-header-fields")
if #header_fields > 0 then
-- We can't escape the headers, mpv won't parse "--http-header-fields='Name: value'" properly
header_fields_arg = "--http-header-fields=" .. table.concat(header_fields, ",")
end
local profile_arg = nil
if thumbnailer_options.mpv_profile ~= "" then
profile_arg = "--profile=" .. thumbnailer_options.mpv_profile
end
local log_arg = "--log-file=" .. output_path .. ".log"
local mpv_command = skip_nil({
"mpv",
-- Hide console output
"--msg-level=all=no",
-- Disable ytdl
(ytdl_disabled and "--no-ytdl" or nil),
-- Pass HTTP headers from current instance
header_fields_arg,
-- Pass User-Agent and Referer - should do no harm even with ytdl active
"--user-agent=" .. mp.get_property_native("user-agent"),
"--referrer=" .. mp.get_property_native("referrer"),
-- Disable hardware decoding
"--hwdec=no",
-- Insert --no-config, --profile=... and --log-file if enabled
(thumbnailer_options.mpv_no_config and "--no-config" or nil),
profile_arg,
(thumbnailer_options.mpv_logs and log_arg or nil),
file_path,
"--start=" .. tostring(timestamp),
"--frames=1",
"--hr-seek=yes",
"--no-audio",
-- Optionally disable subtitles
(thumbnailer_options.mpv_no_sub and "--no-sub" or nil),
("--vf=scale=%d:%d"):format(size.w, size.h),
"--vf-add=format=bgra",
"--of=rawvideo",
"--ovc=rawvideo",
("--o=%s"):format(output_path)
})
return utils.subprocess({args=mpv_command})
end
function create_thumbnail_ffmpeg(file_path, timestamp, size, output_path)
local ffmpeg_command = {
"ffmpeg",
"-loglevel", "quiet",
"-noaccurate_seek",
"-ss", format_time(timestamp, ":"),
"-i", file_path,
"-frames:v", "1",
"-an",
"-vf", ("scale=%d:%d"):format(size.w, size.h),
"-c:v", "rawvideo",
"-pix_fmt", "bgra",
"-f", "rawvideo",
"-y", output_path
}
return utils.subprocess({args=ffmpeg_command})
end
function check_output(ret, output_path, is_mpv)
local log_path = output_path .. ".log"
local success = true
if ret.killed_by_us then
return nil
else
if ret.error or ret.status ~= 0 then
msg.error("Thumbnailing command failed!")
msg.error("mpv process error:", ret.error)
msg.error("Process stdout:", ret.stdout)
if is_mpv then
msg.error("Debug log:", log_path)
end
success = false
end
if not file_exists(output_path) then
msg.error("Output file missing!", output_path)
success = false
end
end
if is_mpv and not thumbnailer_options.mpv_keep_logs then
-- Remove successful debug logs
if success and file_exists(log_path) then
os.remove(log_path)
end
end
return success
end
function do_worker_job(state_json_string, frames_json_string)
msg.debug("Handling given job")
local thumb_state, err = utils.parse_json(state_json_string)
if err then
msg.error("Failed to parse state JSON")
return
end
local thumbnail_indexes, err = utils.parse_json(frames_json_string)
if err then
msg.error("Failed to parse thumbnail frame indexes")
return
end
local thumbnail_func = create_thumbnail_mpv
if not thumbnailer_options.prefer_mpv then
if ExecutableFinder:get_executable_path("ffmpeg") then
thumbnail_func = create_thumbnail_ffmpeg
else
msg.warn("Could not find ffmpeg in PATH! Falling back on mpv.")
end
end
local file_duration = mp.get_property_native("duration")
local file_path = thumb_state.worker_input_path
if thumb_state.is_remote then
if (thumbnail_func == create_thumbnail_ffmpeg) then
msg.warn("Thumbnailing remote path, falling back on mpv.")
end
thumbnail_func = create_thumbnail_mpv
end
local generate_thumbnail_for_index = function(thumbnail_index)
-- Given a 1-based thumbnail index, generate a thumbnail for it based on the thumbnailer state
local thumb_idx = thumbnail_index - 1
msg.debug("Starting work on thumbnail", thumb_idx)
local thumbnail_path = thumb_state.thumbnail_template:format(thumb_idx)
-- Grab the "middle" of the thumbnail duration instead of the very start, and leave some margin in the end
local timestamp = math.min(file_duration - 0.25, (thumb_idx + 0.5) * thumb_state.thumbnail_delta)
mp.commandv("script-message", "mpv_thumbnail_script-progress", tostring(thumbnail_index))
-- The expected size (raw BGRA image)
local thumbnail_raw_size = (thumb_state.thumbnail_size.w * thumb_state.thumbnail_size.h * 4)
local need_thumbnail_generation = false
-- Check if the thumbnail already exists and is the correct size
local thumbnail_file = io.open(thumbnail_path, "rb")
if thumbnail_file == nil then
need_thumbnail_generation = true
else
local existing_thumbnail_filesize = thumbnail_file:seek("end")
if existing_thumbnail_filesize ~= thumbnail_raw_size then
-- Size doesn't match, so (re)generate
msg.warn("Thumbnail", thumb_idx, "did not match expected size, regenerating")
need_thumbnail_generation = true
end
thumbnail_file:close()
end
if need_thumbnail_generation then
local ret = thumbnail_func(file_path, timestamp, thumb_state.thumbnail_size, thumbnail_path, thumb_state.worker_extra)
local success = check_output(ret, thumbnail_path, thumbnail_func == create_thumbnail_mpv)
if success == nil then
-- Killed by us, changing files, ignore
msg.debug("Changing files, subprocess killed")
return true
elseif not success then
-- Real failure
mp.osd_message("Thumbnailing failed, check console for details", 3.5)
return true
end
else
msg.debug("Thumbnail", thumb_idx, "already done!")
end
-- Verify thumbnail size
-- Sometimes ffmpeg will output an empty file when seeking to a "bad" section (usually the end)
thumbnail_file = io.open(thumbnail_path, "rb")
-- Bail if we can't read the file (it should really exist by now, we checked this in check_output!)
if thumbnail_file == nil then
msg.error("Thumbnail suddenly disappeared!")
return true
end
-- Check the size of the generated file
local thumbnail_file_size = thumbnail_file:seek("end")
thumbnail_file:close()
-- Check if the file is big enough
local missing_bytes = math.max(0, thumbnail_raw_size - thumbnail_file_size)
if missing_bytes > 0 then
msg.warn(("Thumbnail missing %d bytes (expected %d, had %d), padding %s"):format(
missing_bytes, thumbnail_raw_size, thumbnail_file_size, thumbnail_path
))
-- Pad the file if it's missing content (eg. ffmpeg seek to file end)
thumbnail_file = io.open(thumbnail_path, "ab")
thumbnail_file:write(string.rep(string.char(0), missing_bytes))
thumbnail_file:close()
end
msg.debug("Finished work on thumbnail", thumb_idx)
mp.commandv("script-message", "mpv_thumbnail_script-ready", tostring(thumbnail_index), thumbnail_path)
end
msg.debug(("Generating %d thumbnails @ %dx%d for %q"):format(
#thumbnail_indexes,
thumb_state.thumbnail_size.w,
thumb_state.thumbnail_size.h,
file_path))
for i, thumbnail_index in ipairs(thumbnail_indexes) do
local bail = generate_thumbnail_for_index(thumbnail_index)
if bail then return end
end
end
-- Set up listeners and keybinds
-- Job listener
mp.register_script_message("mpv_thumbnail_script-job", do_worker_job)
-- Register this worker with the master script
local register_timer = nil
local register_timeout = mp.get_time() + 1.5
local register_function = function()
if mp.get_time() > register_timeout and register_timer then
msg.error("Thumbnail worker registering timed out")
register_timer:stop()
else
msg.debug("Announcing self to master...")
mp.commandv("script-message", "mpv_thumbnail_script-worker", mp.get_script_name())
end
end
register_timer = mp.add_periodic_timer(0.1, register_function)
mp.register_script_message("mpv_thumbnail_script-slaved", function()
msg.debug("Successfully registered with master")
register_timer:stop()
end)

View file

@ -0,0 +1,736 @@
--[[
Copyright (C) 2017 AMM
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
]]--
--[[
mpv_thumbnail_script.lua 0.4.7 - commit 6282073 (branch master)
https://github.com/TheAMM/mpv_thumbnail_script
Built on 2022-02-05 16:00:24
]]--
local assdraw = require 'mp.assdraw'
local msg = require 'mp.msg'
local opt = require 'mp.options'
local utils = require 'mp.utils'
-- Determine platform --
ON_WINDOWS = (package.config:sub(1,1) ~= '/')
-- Some helper functions needed to parse the options --
function isempty(v) return (v == false) or (v == nil) or (v == "") or (v == 0) or (type(v) == "table" and next(v) == nil) end
function divmod (a, b)
return math.floor(a / b), a % b
end
-- Better modulo
function bmod( i, N )
return (i % N + N) % N
end
function join_paths(...)
local sep = ON_WINDOWS and "\\" or "/"
local result = "";
for i, p in pairs({...}) do
if p ~= "" then
if is_absolute_path(p) then
result = p
else
result = (result ~= "") and (result:gsub("[\\"..sep.."]*$", "") .. sep .. p) or p
end
end
end
return result:gsub("[\\"..sep.."]*$", "")
end
-- /some/path/file.ext -> /some/path, file.ext
function split_path( path )
local sep = ON_WINDOWS and "\\" or "/"
local first_index, last_index = path:find('^.*' .. sep)
if last_index == nil then
return "", path
else
local dir = path:sub(0, last_index-1)
local file = path:sub(last_index+1, -1)
return dir, file
end
end
function is_absolute_path( path )
local tmp, is_win = path:gsub("^[A-Z]:\\", "")
local tmp, is_unix = path:gsub("^/", "")
return (is_win > 0) or (is_unix > 0)
end
function Set(source)
local set = {}
for _, l in ipairs(source) do set[l] = true end
return set
end
---------------------------
-- More helper functions --
---------------------------
-- Removes all keys from a table, without destroying the reference to it
function clear_table(target)
for key, value in pairs(target) do
target[key] = nil
end
end
function shallow_copy(target)
local copy = {}
for k, v in pairs(target) do
copy[k] = v
end
return copy
end
-- Rounds to given decimals. eg. round_dec(3.145, 0) => 3
function round_dec(num, idp)
local mult = 10^(idp or 0)
return math.floor(num * mult + 0.5) / mult
end
function file_exists(name)
local f = io.open(name, "rb")
if f ~= nil then
local ok, err, code = f:read(1)
io.close(f)
return code == nil
else
return false
end
end
function path_exists(name)
local f = io.open(name, "rb")
if f ~= nil then
io.close(f)
return true
else
return false
end
end
function create_directories(path)
local cmd
if ON_WINDOWS then
cmd = { args = {"cmd", "/c", "mkdir", path} }
else
cmd = { args = {"mkdir", "-p", path} }
end
utils.subprocess(cmd)
end
-- Find an executable in PATH or CWD with the given name
function find_executable(name)
local delim = ON_WINDOWS and ";" or ":"
local pwd = os.getenv("PWD") or utils.getcwd()
local path = os.getenv("PATH")
local env_path = pwd .. delim .. path -- Check CWD first
local result, filename
for path_dir in env_path:gmatch("[^"..delim.."]+") do
filename = join_paths(path_dir, name)
if file_exists(filename) then
result = filename
break
end
end
return result
end
local ExecutableFinder = { path_cache = {} }
-- Searches for an executable and caches the result if any
function ExecutableFinder:get_executable_path( name, raw_name )
name = ON_WINDOWS and not raw_name and (name .. ".exe") or name
if self.path_cache[name] == nil then
self.path_cache[name] = find_executable(name) or false
end
return self.path_cache[name]
end
-- Format seconds to HH.MM.SS.sss
function format_time(seconds, sep, decimals)
decimals = decimals == nil and 3 or decimals
sep = sep and sep or "."
local s = seconds
local h, s = divmod(s, 60*60)
local m, s = divmod(s, 60)
local second_format = string.format("%%0%d.%df", 2+(decimals > 0 and decimals+1 or 0), decimals)
return string.format("%02d"..sep.."%02d"..sep..second_format, h, m, s)
end
-- Format seconds to 1h 2m 3.4s
function format_time_hms(seconds, sep, decimals, force_full)
decimals = decimals == nil and 1 or decimals
sep = sep ~= nil and sep or " "
local s = seconds
local h, s = divmod(s, 60*60)
local m, s = divmod(s, 60)
if force_full or h > 0 then
return string.format("%dh"..sep.."%dm"..sep.."%." .. tostring(decimals) .. "fs", h, m, s)
elseif m > 0 then
return string.format("%dm"..sep.."%." .. tostring(decimals) .. "fs", m, s)
else
return string.format("%." .. tostring(decimals) .. "fs", s)
end
end
-- Writes text on OSD and console
function log_info(txt, timeout)
timeout = timeout or 1.5
msg.info(txt)
mp.osd_message(txt, timeout)
end
-- Join table items, ala ({"a", "b", "c"}, "=", "-", ", ") => "=a-, =b-, =c-"
function join_table(source, before, after, sep)
before = before or ""
after = after or ""
sep = sep or ", "
local result = ""
for i, v in pairs(source) do
if not isempty(v) then
local part = before .. v .. after
if i == 1 then
result = part
else
result = result .. sep .. part
end
end
end
return result
end
function wrap(s, char)
char = char or "'"
return char .. s .. char
end
-- Wraps given string into 'string' and escapes any 's in it
function escape_and_wrap(s, char, replacement)
char = char or "'"
replacement = replacement or "\\" .. char
return wrap(string.gsub(s, char, replacement), char)
end
-- Escapes single quotes in a string and wraps the input in single quotes
function escape_single_bash(s)
return escape_and_wrap(s, "'", "'\\''")
end
-- Returns (a .. b) if b is not empty or nil
function joined_or_nil(a, b)
return not isempty(b) and (a .. b) or nil
end
-- Put items from one table into another
function extend_table(target, source)
for i, v in pairs(source) do
table.insert(target, v)
end
end
-- Creates a handle and filename for a temporary random file (in current directory)
function create_temporary_file(base, mode, suffix)
local handle, filename
suffix = suffix or ""
while true do
filename = base .. tostring(math.random(1, 5000)) .. suffix
handle = io.open(filename, "r")
if not handle then
handle = io.open(filename, mode)
break
end
io.close(handle)
end
return handle, filename
end
function get_processor_count()
local proc_count
if ON_WINDOWS then
proc_count = tonumber(os.getenv("NUMBER_OF_PROCESSORS"))
else
local cpuinfo_handle = io.open("/proc/cpuinfo")
if cpuinfo_handle ~= nil then
local cpuinfo_contents = cpuinfo_handle:read("*a")
local _, replace_count = cpuinfo_contents:gsub('processor', '')
proc_count = replace_count
end
end
if proc_count and proc_count > 0 then
return proc_count
else
return nil
end
end
function substitute_values(string, values)
local substitutor = function(match)
if match == "%" then
return "%"
else
-- nil is discarded by gsub
return values[match]
end
end
local substituted = string:gsub('%%(.)', substitutor)
return substituted
end
-- ASS HELPERS --
function round_rect_top( ass, x0, y0, x1, y1, r )
local c = 0.551915024494 * r -- circle approximation
ass:move_to(x0 + r, y0)
ass:line_to(x1 - r, y0) -- top line
if r > 0 then
ass:bezier_curve(x1 - r + c, y0, x1, y0 + r - c, x1, y0 + r) -- top right corner
end
ass:line_to(x1, y1) -- right line
ass:line_to(x0, y1) -- bottom line
ass:line_to(x0, y0 + r) -- left line
if r > 0 then
ass:bezier_curve(x0, y0 + r - c, x0 + r - c, y0, x0 + r, y0) -- top left corner
end
end
function round_rect(ass, x0, y0, x1, y1, rtl, rtr, rbr, rbl)
local c = 0.551915024494
ass:move_to(x0 + rtl, y0)
ass:line_to(x1 - rtr, y0) -- top line
if rtr > 0 then
ass:bezier_curve(x1 - rtr + rtr*c, y0, x1, y0 + rtr - rtr*c, x1, y0 + rtr) -- top right corner
end
ass:line_to(x1, y1 - rbr) -- right line
if rbr > 0 then
ass:bezier_curve(x1, y1 - rbr + rbr*c, x1 - rbr + rbr*c, y1, x1 - rbr, y1) -- bottom right corner
end
ass:line_to(x0 + rbl, y1) -- bottom line
if rbl > 0 then
ass:bezier_curve(x0 + rbl - rbl*c, y1, x0, y1 - rbl + rbl*c, x0, y1 - rbl) -- bottom left corner
end
ass:line_to(x0, y0 + rtl) -- left line
if rtl > 0 then
ass:bezier_curve(x0, y0 + rtl - rtl*c, x0 + rtl - rtl*c, y0, x0 + rtl, y0) -- top left corner
end
end
local SCRIPT_NAME = "mpv_thumbnail_script"
local default_cache_base = ON_WINDOWS and os.getenv("TEMP") or "/tmp/"
local thumbnailer_options = {
-- The thumbnail directory
cache_directory = join_paths(default_cache_base, "mpv_thumbs_cache"),
------------------------
-- Generation options --
------------------------
-- Automatically generate the thumbnails on video load, without a keypress
autogenerate = true,
-- Only automatically thumbnail videos shorter than this (seconds)
autogenerate_max_duration = 3600, -- 1 hour
-- SHA1-sum filenames over this length
-- It's nice to know what files the thumbnails are (hence directory names)
-- but long URLs may approach filesystem limits.
hash_filename_length = 128,
-- Use mpv to generate thumbnail even if ffmpeg is found in PATH
-- ffmpeg does not handle ordered chapters (MKVs which rely on other MKVs)!
-- mpv is a bit slower, but has better support overall (eg. subtitles in the previews)
prefer_mpv = true,
-- Explicitly disable subtitles on the mpv sub-calls
mpv_no_sub = false,
-- Add a "--no-config" to the mpv sub-call arguments
mpv_no_config = false,
-- Add a "--profile=<mpv_profile>" to the mpv sub-call arguments
-- Use "" to disable
mpv_profile = "",
-- Output debug logs to <thumbnail_path>.log, ala <cache_directory>/<video_filename>/000000.bgra.log
-- The logs are removed after successful encodes, unless you set mpv_keep_logs below
mpv_logs = true,
-- Keep all mpv logs, even the succesfull ones
mpv_keep_logs = false,
-- Disable the built-in keybind ("T") to add your own
disable_keybinds = false,
---------------------
-- Display options --
---------------------
-- Move the thumbnail up or down
-- For example:
-- topbar/bottombar: 24
-- rest: 0
vertical_offset = 24,
-- Adjust background padding
-- Examples:
-- topbar: 0, 10, 10, 10
-- bottombar: 10, 0, 10, 10
-- slimbox/box: 10, 10, 10, 10
pad_top = 10,
pad_bot = 0,
pad_left = 10,
pad_right = 10,
-- If true, pad values are screen-pixels. If false, video-pixels.
pad_in_screenspace = true,
-- Calculate pad into the offset
offset_by_pad = true,
-- Background color in BBGGRR
background_color = "000000",
-- Alpha: 0 - fully opaque, 255 - transparent
background_alpha = 80,
-- Keep thumbnail on the screen near left or right side
constrain_to_screen = true,
-- Do not display the thumbnailing progress
hide_progress = false,
-----------------------
-- Thumbnail options --
-----------------------
-- The maximum dimensions of the thumbnails (pixels)
thumbnail_width = 200,
thumbnail_height = 200,
-- The thumbnail count target
-- (This will result in a thumbnail every ~10 seconds for a 25 minute video)
thumbnail_count = 150,
-- The above target count will be adjusted by the minimum and
-- maximum time difference between thumbnails.
-- The thumbnail_count will be used to calculate a target separation,
-- and min/max_delta will be used to constrict it.
-- In other words, thumbnails will be:
-- at least min_delta seconds apart (limiting the amount)
-- at most max_delta seconds apart (raising the amount if needed)
min_delta = 5,
-- 120 seconds aka 2 minutes will add more thumbnails when the video is over 5 hours!
max_delta = 90,
-- Overrides for remote urls (you generally want less thumbnails!)
-- Thumbnailing network paths will be done with mpv
-- Allow thumbnailing network paths (naive check for "://")
thumbnail_network = false,
-- Override thumbnail count, min/max delta
remote_thumbnail_count = 60,
remote_min_delta = 15,
remote_max_delta = 120,
-- Try to grab the raw stream and disable ytdl for the mpv subcalls
-- Much faster than passing the url to ytdl again, but may cause problems with some sites
remote_direct_stream = true,
}
read_options(thumbnailer_options, SCRIPT_NAME)
function skip_nil(tbl)
local n = {}
for k, v in pairs(tbl) do
table.insert(n, v)
end
return n
end
function create_thumbnail_mpv(file_path, timestamp, size, output_path, options)
options = options or {}
local ytdl_disabled = not options.enable_ytdl and (mp.get_property_native("ytdl") == false
or thumbnailer_options.remote_direct_stream)
local header_fields_arg = nil
local header_fields = mp.get_property_native("http-header-fields")
if #header_fields > 0 then
-- We can't escape the headers, mpv won't parse "--http-header-fields='Name: value'" properly
header_fields_arg = "--http-header-fields=" .. table.concat(header_fields, ",")
end
local profile_arg = nil
if thumbnailer_options.mpv_profile ~= "" then
profile_arg = "--profile=" .. thumbnailer_options.mpv_profile
end
local log_arg = "--log-file=" .. output_path .. ".log"
local mpv_command = skip_nil({
"mpv",
-- Hide console output
"--msg-level=all=no",
-- Disable ytdl
(ytdl_disabled and "--no-ytdl" or nil),
-- Pass HTTP headers from current instance
header_fields_arg,
-- Pass User-Agent and Referer - should do no harm even with ytdl active
"--user-agent=" .. mp.get_property_native("user-agent"),
"--referrer=" .. mp.get_property_native("referrer"),
-- Disable hardware decoding
"--hwdec=no",
-- Insert --no-config, --profile=... and --log-file if enabled
(thumbnailer_options.mpv_no_config and "--no-config" or nil),
profile_arg,
(thumbnailer_options.mpv_logs and log_arg or nil),
file_path,
"--start=" .. tostring(timestamp),
"--frames=1",
"--hr-seek=yes",
"--no-audio",
-- Optionally disable subtitles
(thumbnailer_options.mpv_no_sub and "--no-sub" or nil),
("--vf=scale=%d:%d"):format(size.w, size.h),
"--vf-add=format=bgra",
"--of=rawvideo",
"--ovc=rawvideo",
("--o=%s"):format(output_path)
})
return utils.subprocess({args=mpv_command})
end
function create_thumbnail_ffmpeg(file_path, timestamp, size, output_path)
local ffmpeg_command = {
"ffmpeg",
"-loglevel", "quiet",
"-noaccurate_seek",
"-ss", format_time(timestamp, ":"),
"-i", file_path,
"-frames:v", "1",
"-an",
"-vf", ("scale=%d:%d"):format(size.w, size.h),
"-c:v", "rawvideo",
"-pix_fmt", "bgra",
"-f", "rawvideo",
"-y", output_path
}
return utils.subprocess({args=ffmpeg_command})
end
function check_output(ret, output_path, is_mpv)
local log_path = output_path .. ".log"
local success = true
if ret.killed_by_us then
return nil
else
if ret.error or ret.status ~= 0 then
msg.error("Thumbnailing command failed!")
msg.error("mpv process error:", ret.error)
msg.error("Process stdout:", ret.stdout)
if is_mpv then
msg.error("Debug log:", log_path)
end
success = false
end
if not file_exists(output_path) then
msg.error("Output file missing!", output_path)
success = false
end
end
if is_mpv and not thumbnailer_options.mpv_keep_logs then
-- Remove successful debug logs
if success and file_exists(log_path) then
os.remove(log_path)
end
end
return success
end
function do_worker_job(state_json_string, frames_json_string)
msg.debug("Handling given job")
local thumb_state, err = utils.parse_json(state_json_string)
if err then
msg.error("Failed to parse state JSON")
return
end
local thumbnail_indexes, err = utils.parse_json(frames_json_string)
if err then
msg.error("Failed to parse thumbnail frame indexes")
return
end
local thumbnail_func = create_thumbnail_mpv
if not thumbnailer_options.prefer_mpv then
if ExecutableFinder:get_executable_path("ffmpeg") then
thumbnail_func = create_thumbnail_ffmpeg
else
msg.warn("Could not find ffmpeg in PATH! Falling back on mpv.")
end
end
local file_duration = mp.get_property_native("duration")
local file_path = thumb_state.worker_input_path
if thumb_state.is_remote then
if (thumbnail_func == create_thumbnail_ffmpeg) then
msg.warn("Thumbnailing remote path, falling back on mpv.")
end
thumbnail_func = create_thumbnail_mpv
end
local generate_thumbnail_for_index = function(thumbnail_index)
-- Given a 1-based thumbnail index, generate a thumbnail for it based on the thumbnailer state
local thumb_idx = thumbnail_index - 1
msg.debug("Starting work on thumbnail", thumb_idx)
local thumbnail_path = thumb_state.thumbnail_template:format(thumb_idx)
-- Grab the "middle" of the thumbnail duration instead of the very start, and leave some margin in the end
local timestamp = math.min(file_duration - 0.25, (thumb_idx + 0.5) * thumb_state.thumbnail_delta)
mp.commandv("script-message", "mpv_thumbnail_script-progress", tostring(thumbnail_index))
-- The expected size (raw BGRA image)
local thumbnail_raw_size = (thumb_state.thumbnail_size.w * thumb_state.thumbnail_size.h * 4)
local need_thumbnail_generation = false
-- Check if the thumbnail already exists and is the correct size
local thumbnail_file = io.open(thumbnail_path, "rb")
if thumbnail_file == nil then
need_thumbnail_generation = true
else
local existing_thumbnail_filesize = thumbnail_file:seek("end")
if existing_thumbnail_filesize ~= thumbnail_raw_size then
-- Size doesn't match, so (re)generate
msg.warn("Thumbnail", thumb_idx, "did not match expected size, regenerating")
need_thumbnail_generation = true
end
thumbnail_file:close()
end
if need_thumbnail_generation then
local ret = thumbnail_func(file_path, timestamp, thumb_state.thumbnail_size, thumbnail_path, thumb_state.worker_extra)
local success = check_output(ret, thumbnail_path, thumbnail_func == create_thumbnail_mpv)
if success == nil then
-- Killed by us, changing files, ignore
msg.debug("Changing files, subprocess killed")
return true
elseif not success then
-- Real failure
mp.osd_message("Thumbnailing failed, check console for details", 3.5)
return true
end
else
msg.debug("Thumbnail", thumb_idx, "already done!")
end
-- Verify thumbnail size
-- Sometimes ffmpeg will output an empty file when seeking to a "bad" section (usually the end)
thumbnail_file = io.open(thumbnail_path, "rb")
-- Bail if we can't read the file (it should really exist by now, we checked this in check_output!)
if thumbnail_file == nil then
msg.error("Thumbnail suddenly disappeared!")
return true
end
-- Check the size of the generated file
local thumbnail_file_size = thumbnail_file:seek("end")
thumbnail_file:close()
-- Check if the file is big enough
local missing_bytes = math.max(0, thumbnail_raw_size - thumbnail_file_size)
if missing_bytes > 0 then
msg.warn(("Thumbnail missing %d bytes (expected %d, had %d), padding %s"):format(
missing_bytes, thumbnail_raw_size, thumbnail_file_size, thumbnail_path
))
-- Pad the file if it's missing content (eg. ffmpeg seek to file end)
thumbnail_file = io.open(thumbnail_path, "ab")
thumbnail_file:write(string.rep(string.char(0), missing_bytes))
thumbnail_file:close()
end
msg.debug("Finished work on thumbnail", thumb_idx)
mp.commandv("script-message", "mpv_thumbnail_script-ready", tostring(thumbnail_index), thumbnail_path)
end
msg.debug(("Generating %d thumbnails @ %dx%d for %q"):format(
#thumbnail_indexes,
thumb_state.thumbnail_size.w,
thumb_state.thumbnail_size.h,
file_path))
for i, thumbnail_index in ipairs(thumbnail_indexes) do
local bail = generate_thumbnail_for_index(thumbnail_index)
if bail then return end
end
end
-- Set up listeners and keybinds
-- Job listener
mp.register_script_message("mpv_thumbnail_script-job", do_worker_job)
-- Register this worker with the master script
local register_timer = nil
local register_timeout = mp.get_time() + 1.5
local register_function = function()
if mp.get_time() > register_timeout and register_timer then
msg.error("Thumbnail worker registering timed out")
register_timer:stop()
else
msg.debug("Announcing self to master...")
mp.commandv("script-message", "mpv_thumbnail_script-worker", mp.get_script_name())
end
end
register_timer = mp.add_periodic_timer(0.1, register_function)
mp.register_script_message("mpv_thumbnail_script-slaved", function()
msg.debug("Successfully registered with master")
register_timer:stop()
end)

View file

@ -0,0 +1,11 @@
local ov = mp.create_osd_overlay('ass-events')
ov.data = [[{\an5\p1\alpha&H79\1c&Hffffff&\3a&Hff\pos(760,440)}]] ..
[[m-125 -75 l 2 2 l -125 75]]
mp.observe_property('pause', 'bool', function(_, paused)
mp.add_timeout(0.1, function()
if paused then ov:update()
else ov:remove() end
end)
end)

View file

@ -0,0 +1,657 @@
This file intends to give a big picture overview of how mpv is structured.
player/*.c:
Essentially makes up the player applications, including the main() function
and the playback loop.
Generally, it accesses all other subsystems, initializes them, and pushes
data between them during playback.
The structure is as follows (as of commit e13c05366557cb):
* main():
* basic initializations (e.g. init_libav() and more)
* pre-parse command line (verbosity level, config file locations)
* load config files (parse_cfgfiles())
* parse command line, add files from the command line to playlist
(m_config_parse_mp_command_line())
* check help options etc. (call handle_help_options()), possibly exit
* call mp_play_files() function that works down the playlist:
* run idle loop (idle_loop()), until there are files in the
playlist or an exit command was given (only if --idle it set)
* actually load and play a file in play_current_file():
* run all the dozens of functions to load the file and
initialize playback
* run a small loop that does normal playback, until the file is
done or a command terminates playback
(on each iteration, run_playloop() is called, which is rather
big and complicated - it decodes some audio and video on
each frame, waits for input, etc.)
* uninitialize playback
* determine next entry on the playlist to play
* loop, or exit if no next file or quit is requested
(see enum stop_play_reason)
* call mp_destroy()
* run_playloop():
* calls fill_audio_out_buffers()
This checks whether new audio needs to be decoded, and pushes it
to the AO.
* calls write_video()
Decode new video, and push it to the VO.
* determines whether playback of the current file has ended
* determines when to start playback after seeks
* and calls a whole lot of other stuff
(Really, this function does everything.)
Things worth saying about the playback core:
- most state is in MPContext (core.h), which is not available to the
subsystems (and should not be made available)
- the currently played tracks are in mpctx->current_tracks, and decoder
state in track.dec/d_sub
- the other subsystems rarely call back into the frontend, and the frontend
polls them instead (probably a good thing)
- one exceptions are wakeup callbacks, which notify a "higher" component
of a changed situation in a subsystem
I like to call the player/*.c files the "frontend".
ta.h & ta.c:
Hierarchical memory manager inspired by talloc from Samba. It's like a
malloc() with more features. Most importantly, each talloc allocation can
have a parent, and if the parent is free'd, all children will be free'd as
well. The parent is an arbitrary talloc allocation. It's either set by the
allocation call by passing a talloc parent, usually as first argument to the
allocation function. It can also be set or reset later by other calls (at
least talloc_steal()). A talloc allocation that is used as parent is often
called a talloc context.
One very useful feature of talloc is fast tracking of memory leaks. ("Fast"
as in it doesn't require valgrind.) You can enable it by setting the
MPV_LEAK_REPORT environment variable to "1":
export MPV_LEAK_REPORT=1
Or permanently by building with --enable-ta-leak-report.
This will list all unfree'd allocations on exit.
Documentation can be found here:
http://git.samba.org/?p=samba.git;a=blob;f=lib/talloc/talloc.h;hb=HEAD
For some reason, we're still using API-compatible wrappers instead of TA
directly. The talloc wrapper has only a subset of the functionality, and
in particular the wrappers abort() on memory allocation failure.
Note: unlike tcmalloc, jemalloc, etc., talloc() is not actually a malloc
replacement. It works on top of system malloc and provides additional
features that are supposed to make memory management easier.
player/command.c:
This contains the implementation for client API commands and properties.
Properties are essentially dynamic variables changed by certain commands.
This is basically responsible for all user commands, like initiating
seeking, switching tracks, etc. It calls into other player/*.c files,
where most of the work is done, but also calls other parts of mpv.
player/core.h:
Data structures and function prototypes for most of player/*.c. They are
usually not accessed by other parts of mpv for the sake of modularization.
player/client.c:
This implements the client API (libmpv/client.h). For the most part, this
just calls into other parts of the player. This also manages a ringbuffer
of events from player to clients.
options/options.h, options/options.c
options.h contains the global option struct MPOpts. The option declarations
(option names, types, and MPOpts offsets for the option parser) are in
options.c. Most default values for options and MPOpts are in
mp_default_opts at the end of options.c.
MPOpts is unfortunately quite monolithic, but is being incrementally broken
up into sub-structs. Many components have their own sub-option structs
separate from MPOpts. New options should be bound to the component that uses
them. Add a new option table/struct if needed.
The global MPOpts still contains the sub-structs as fields, which serves to
link them to the option parser. For example, an entry like this may be
typical:
{"", OPT_SUBSTRUCT(demux_opts, demux_conf)},
This directs the option access code to include all options in demux_conf
into the global option list, with no prefix (""), and as part of the
MPOpts.demux_opts field. The MPOpts.demux_opts field is actually not
accessed anywhere, and instead demux.c does this:
struct m_config_cache *opts_cache =
m_config_cache_alloc(demuxer, global, &demux_conf);
struct demux_opts *opts = opts_cache->opts;
... to get a copy of its options.
See m_config.h (below) how to access options.
The actual option parser is spread over m_option.c, m_config.c, and
parse_commandline.c, and uses the option table in options.c.
options/m_config.h & m_config.c:
Code for querying and managing options. This (unfortunately) contains both
declarations for the "legacy-ish" global m_config struct, and ways to access
options in a threads-safe way anywhere, like m_config_cache_alloc().
m_config_cache_alloc() lets anyone read, observe, and write options in any
thread. The only state it needs is struct mpv_global, which is an opaque
type that can be passed "down" the component hierarchy. For safety reasons,
you should not pass down any pointers to option structs (like MPOpts), but
instead pass down mpv_global, and use m_config_cache_alloc() (or similar)
to get a synchronized copy of the options.
input/input.c:
This translates keyboard input coming from VOs and other sources (such
as remote control devices like Apple IR or client API commands) to the
key bindings listed in the user's (or the builtin) input.conf and turns
them into items of type struct mp_cmd. These commands are queued, and read
by playloop.c. They get pushed with run_command() to command.c.
Note that keyboard input and commands used by the client API are the same.
The client API only uses the command parser though, and has its own queue
of input commands somewhere else.
common/msg.h:
All terminal output must go through mp_msg().
stream/*:
File input is implemented here. stream.h/.c provides a simple stream based
interface (like reading a number of bytes at a given offset). mpv can
also play from http streams and such, which is implemented here.
E.g. if mpv sees "http://something" on the command line, it will pick
stream_lavf.c based on the prefix, and pass the rest of the filename to it.
Some stream inputs are quite special: stream_dvd.c turns DVDs into mpeg
streams (DVDs are actually a bunch of vob files etc. on a filesystem),
stream_tv.c provides TV input including channel switching.
Some stream inputs are just there to invoke special demuxers, like
stream_mf.c. (Basically to make the prefix "mf://" do something special.)
demux/:
Demuxers split data streams into audio/video/sub streams, which in turn
are split in packets. Packets (see demux_packet.h) are mostly byte chunks
tagged with a playback time (PTS). These packets are passed to the decoders.
Most demuxers have been removed from this fork, and the only important and
"actual" demuxers left are demux_mkv.c and demux_lavf.c (uses libavformat).
There are some pseudo demuxers like demux_cue.c.
The main interface is in demux.h. The stream headers are in stheader.h.
There is a stream header for each audio/video/sub stream, and each of them
holds codec information about the stream and other information.
demux.c is a bit big, the main reason being that it contains the demuxer
cache, which is implemented as a list of packets. The cache is complex
because it support seeking, multiple ranges, prefetching, and so on.
video/:
This contains several things related to audio/video decoding, as well as
video filters.
mp_image.h and img_format.h define how mpv stores decoded video frames
internally.
video/decode/:
vd_*.c are video decoders. (There's only vd_lavc.c left.) dec_video.c
handles most of connecting the frontend with the actual decoder.
video/filter/:
vf_*.c and vf.c form the video filter chain. They are fed by the video
decoder, and output the filtered images to the VOs though vf_vo.c. By
default, no video filters (except vf_vo) are used. vf_scale is automatically
inserted if the video output can't handle the video format used by the
decoder.
video/out/:
Video output. They also create GUI windows and handle user input. In most
cases, the windowing code is shared among VOs, like x11_common.c for X11 and
w32_common.c for Windows. The VOs stand between frontend and windowing code.
vo_gpu can pick a windowing system at runtime, e.g. the same binary can
provide both X11 and Cocoa support on OSX.
VOs can be reconfigured at runtime. A vo_reconfig() call can change the video
resolution and format, without destroying the window.
vo_gpu should be taken as reference.
audio/:
format.h/format.c define the uncompressed audio formats. (As well as some
compressed formats used for spdif.)
audio/decode/:
ad_*.c and dec_audio.c handle audio decoding. ad_lavc.c is the
decoder using ffmpeg. ad_spdif.c is not really a decoder, but is used for
compressed audio passthrough.
audio/filter/:
Audio filter chain. af_lavrresample is inserted if any form of conversion
between audio formats is needed.
audio/out/:
Audio outputs.
Unlike VOs, AOs can't be reconfigured on a format change. On audio format
changes, the AO will simply be closed and re-opened.
There are wrappers to support for two types of audio APIs: push.c and
pull.c. ao.c calls into one of these. They contain generic code to deal
with the data flow these APIs impose.
Note that mpv synchronizes the video to the audio. That's the reason
why buggy audio drivers can have a bad influence on playback quality.
sub/:
Contains subtitle and OSD rendering.
osd.c/.h is actually the OSD code. It queries dec_sub.c to retrieve
decoded/rendered subtitles. osd_libass.c is the actual implementation of
the OSD text renderer (which uses libass, and takes care of all the tricky
fontconfig/freetype API usage and text layouting).
The VOs call osd.c to render OSD and subtitle (via e.g. osd_draw()). osd.c
in turn asks dec_sub.c for subtitle overlay bitmaps, which relays the
request to one of the sd_*.c subtitle decoders/renderers.
Subtitle loading is in demux/. The MPlayer subreader.c is mostly gone - parts
of it survive in demux_subreader.c. It's used as last fallback, or to handle
some text subtitle types on Libav. It should go away eventually. Normally,
subtitles are loaded via demux_lavf.c.
The subtitles are passed to dec_sub.c and the subtitle decoders in sd_*.c
as they are demuxed. All text subtitles are rendered by sd_ass.c. If text
subtitles are not in the ASS format, the libavcodec subtitle converters are
used (lavc_conv.c).
Text subtitles can be preloaded, in which case they are read fully as soon
as the subtitle is selected. In this case, they are effectively stored in
sd_ass.c's internal state.
etc/:
The file input.conf is actually integrated into the mpv binary by the
build system. It contains the default keybindings.
Best practices and Concepts within mpv
======================================
General contribution etc.
-------------------------
See: DOCS/contribute.md
Error checking
--------------
If an error is relevant, it should be handled. If it's interesting, log the
error. However, mpv often keeps errors silent and reports failures somewhat
coarsely by propagating them upwards the caller chain. This is OK, as long as
the errors are not very interesting, or would require a developer to debug it
anyway (in which case using a debugger would be more convenient, and the
developer would need to add temporary debug printfs to get extremely detailed
information which would not be appropriate during normal operation).
Basically, keep a balance on error reporting. But always check them, unless you
have a good argument not to.
Memory allocation errors (OOM) are a special class of errors. Normally such
allocation failures are not handled "properly". Instead, abort() is called.
(New code should use MP_HANDLE_OOM() for this.) This is done out of laziness and
for convenience, and due to the fact that MPlayer/mplayer2 never handled it
correctly. (MPlayer varied between handling it correctly, trying to do so but
failing, and just not caring, while mplayer2 started using abort() for it.)
This is justifiable in a number of ways. Error handling paths are notoriously
untested and buggy, so merely having them won't make your program more reliable.
Having these error handling paths also complicates non-error code, due to the
need to roll back state at any point after a memory allocation.
Take any larger body of code, that is supposed to handle OOM, and test whether
the error paths actually work, for example by overriding malloc with a version
that randomly fails. You will find bugs quickly, and often they will be very
annoying to fix (if you can even reproduce them).
In addition, a clear indication that something went wrong may be missing. On
error your program may exhibit "degraded" behavior by design. Consider a video
encoder dropping frames somewhere in the middle of a video due to temporary
allocation failures, instead of just exiting with an errors. In other cases, it
may open conceptual security holes. Failing fast may be better.
mpv uses GPU APIs, which may be break on allocation errors (because driver
authors will have the same issues as described here), or don't even have a real
concept for dealing with OOM (OpenGL).
libmpv is often used by GUIs, which I predict always break if OOM happens.
Last but not least, OSes like Linux use "overcommit", which basically means that
your program may crash any time OOM happens, even if it doesn't use malloc() at
all!
But still, don't just assume malloc() always succeeds. Use MP_HANDLE_OOM(). The
ta* APIs do this for you. The reason for this is that dereferencing a NULL
pointer can have security relevant consequences if large offsets are involved.
Also, a clear error message is better than a random segfault.
Some big memory allocations are checked anyway. For example, all code must
assume that allocating video frames or packets can fail. (The above example
of dropping video frames during encoding is entirely possible in mpv.)
Undefined behavior
------------------
Undefined behavior (UB) is a concept in the C language. C is famous for being a
language that makes it almost impossible to write working code, because
undefined behavior is so easily triggered, compilers will happily abuse it to
generate "faster" code, debugging tools will shout at you, and sometimes it
even means your code doesn't work.
There is a lot of literature on this topic. Read it.
(In C's defense, UB exists in other languages too, but since they're not used
for low level infrastructure, and/or these languages are at times not rigorously
defined, simply nobody cares. However, the C standard committee is still guilty
for not addressing this. I'll admit that I can't even tell from the standard's
gibberish whether some specific behavior is UB or not. It's written like tax
law.)
In mpv, we generally try to avoid undefined behavior. For one, we want portable
and reliable operation. But more importantly, we want clean output from
debugging tools, in order to find real bugs more quickly and effectively.
Avoid the "works in practice" argument. Once debugging tools come into play, or
simply when "in practice" stops being true, this will all get back to you in a
bad way.
Global state, library safety
----------------------------
Mutable global state is when code uses global variables that are not read-only.
This must be avoided in mpv. Always use context structs that the caller of
your code needs to allocate, and whose pointers are passed to your functions.
Library safety means that your code (or library) can be used by a library
without causing conflicts with other library users in the same process. To any
piece of code, a "safe" library's API can simply be used, without having to
worry about other API users that may be around somewhere.
Libraries are often not library safe, because they they use global mutable state
or other "global" resources. Typical examples include use of signals, simple
global variables (like hsearch() in libc), or internal caches not protected by
locks.
A surprisingly high number of libraries are not library safe because they need
global initialization. Typically they provide an API function, which
"initializes" the library, and which must be called before calling any other
API functions. Often, you are to provide global configuration parameters, which
can change the behavior of the library. If two libraries A and B use library C,
but A and B initialize C with different parameters, something "bad" may happen.
In addition, these global initialization functions are often not thread-safe. So
if A and B try to initialize C at the same time (from different threads and
without knowing about each other), it may cause undefined behavior. (libcurl is
a good example of both of these issues. FFmpeg and some TLS libraries used to be
affected, but improved.)
This is so bad because library A and B from the previous example most likely
have no way to cooperate, because they're from different authors and have no
business knowing each others. They'd need a library D, which wraps library C
in a safe way. Unfortunately, typically something worse happens: libraries get
"infected" by the unsafeness of its sub-libraries, and export a global init API
just to initialize the sub-libraries. In the previous example, libraries A and B
would export global init APIs just to init library C, even though the rest of
A/B are clean and library safe. (Again, libcurl is an example of this, if you
subtract other historic anti-features.)
The main problem with library safety is that its lack propagates to all
libraries using the library.
We require libmpv to be library safe. This is not really possible, because some
libraries are not library safe (FFmpeg, Xlib, partially ALSA). However, for
ideological reasons, there is no global init API, and best effort is made to try
to avoid problems.
libmpv has some features that are not library safe, but which are disabled by
default (such as terminal usage aka stdout, or JSON IPC blocking SIGPIPE for
internal convenience).
A notable, very disgustingly library unsafe behavior of libmpv is calling
abort() on some memory allocation failure. See error checking section.
Logging
-------
All logging and terminal output in mpv goes through the functions and macros
provided in common/msg.h. This is in part for library safety, and in part to
make sure users can silence all output, or to redirect the output elsewhere,
like a log file or the internal console.lua script.
Locking
-------
See generally available literature. In mpv, we use pthread for this.
Always keep locking clean. Don't skip locking just because it will work "in
practice". (See undefined behavior section.) If your use case is simple, you may
use C11 atomics (osdep/atomic.h for partial C99 support), but most likely you
will only hurt yourself and others.
Always make clear which fields in a struct are protected by which lock. If a
field is immutable, or simply not thread-safe (e.g. state for a single worker
thread), document it as well.
Internal mpv APIs are assumed to be not thread-safe by default. If they have
special guarantees (such as being usable by more than one thread at a time),
these should be explicitly documented.
All internal mpv APIs must be free of global state. Even if a component is not
thread-safe, multiple threads can use _different_ instances of it without any
locking.
On a side note, recursive locks may seem convenient at first, but introduce
additional problems with condition variables and locking hierarchies. They
should be avoided.
Locking hierarchy
-----------------
A simple way to avoid deadlocks with classic locking is to define a locking
hierarchy or lock order. If all threads acquire locks in the same order, no
deadlocks will happen.
For example, a "leaf" lock is a lock that is below all other locks in the
hierarchy. You can acquire it any time, as long as you don't acquire other
locks while holding it.
Unfortunately, C has no way to declare or check the lock order, so you should at
least document it.
In addition, try to avoid exposing locks to the outside. Making the declaration
of a lock private to a specific .c file (and _not_ exporting accessors or
lock/unlock functions that manipulate the lock) is a good idea. Your component's
API may acquire internal locks, but should release them when returning. Keeping
the entire locking in a single file makes it easy to check it.
Avoiding callback hell
----------------------
mpv code is separated in components, like the "frontend" (i.e. MPContext mpctx),
VOs, AOs, demuxers, and more. The frontend usually calls "down" the usage
hierarchy: mpctx almost on top, then things like vo/ao, and utility code on the
very bottom.
"Callback hell" is when when components call both up and down the hierarchy,
which for example leads to accidentally recursion, reentrancy problems, or
locking nightmares. This is avoided by (mostly) calling only down the hierarchy.
Basically the call graph forms a DAG. The other direction is handled by event
queues, wakeup callbacks, and similar mechanisms.
Typically, a component provides an API, and does not know anything about its
user. The API user (component higher in the hierarchy) polls the state of the
lower component when needed.
This also enforces some level of modularization, and with some luck the locking
hierarchy. (Basically, locks of lower components automatically become leaf
locks.) Another positive effect is simpler memory management.
(Also see e.g.: http://250bpm.com/blog:24)
Wakeup callbacks
----------------
This is a common concept in mpv. Even the public API uses it. It's used when an
API has internal threads (or otherwise triggers asynchronous events), but the
component call hierarchy needs to be kept. The wakeup callback is the only
exception to the call hierarchy, and always calls up.
For example, vo spawns a thread that the API user (the mpv frontend) does not
need to know about. vo simply provides a single-threaded API (or that looks like
one). This API needs a way to notify the API user of new events. But the vo
event producer is on the vo thread - it can't simply invoke a callback back into
the API user, because then the API user has to deal with locking, despite not
using threads. In addition, this will probably cause problems like mentioned in
the "callback hell" section, especially lock order issues.
The solution is the wakeup callback. It merely unblocks the API user from
waiting, and the API user then uses the normal vo API to examine whether or
which state changed. As a concept, it documents what a wakeup callback is
allowed to do and what not, to avoid the aforementioned problems.
Generally, you are not allowed to call any API from the wakeup callback. You
just do whatever is needed to unblock your thread. For example, if it's waiting
on a mutex/condition variable, acquire the mutex, set a change flag, signal
the condition variable, unlock, return. (This mutex must not be held when
calling the API. It must be a leaf lock.)
Restricting the wakeup callback like this sidesteps any reentrancy issues and
other complexities. The API implementation can simply hold internal (and
non-recursive) locks while invoking the wakeup callback.
The API user still needs to deal with locking (probably), but there's only the
need to implement a single "receiver", that can handle the entire API of the
used component. (Or multiple APIs - MPContext for example has only 1 wakeup
callback that handles all AOs, VOs, input, demuxers, and more. It simple re-runs
the playloop.)
You could get something more advanced by turning this into a message queue. The
API would append a message to the queue, and the API user can read it. But then
you still need a way to "wakeup" the API user (unless you force the API user
to block on your API, which will make things inconvenient for the API user). You
also need to worry about what happens if the message queue overruns (you either
lose messages or have unbounded memory usage). In the mpv public API, the
distinction between message queue and wakeup callback is sort of blurry, because
it does provide a message queue, but an additional wakeup callback, so API
users are not required to call mpv_wait_event() with a high timeout.
mpv itself prefers using wakeup callbacks over a generic event queue, because
most times an event queue is not needed (or complicates things), and it is
better to do it manually.
(You could still abstract the API user side of wakeup callback handling, and
avoid reimplementing it all the time. Although mp_dispatch_queue already
provides mechanisms for this.)
Condition variables
-------------------
They're used whenever a thread needs to wait for something, without nonsense
like sleep calls or busy waiting. mpv uses the standard pthread API for this.
There's a lot of literature on it. Read it.
For initial understanding, it may be helpful to know that condition variables
are not variables that signal a condition. pthread_cond_t does not have any
state per-se. Maybe pthread_cond_t would better be named pthread_interrupt_t,
because its sole purpose is to interrupt a thread waiting via pthread_cond_wait()
(or similar). The "something" in "waiting for something" can be called
predicate (to avoid confusing it with "condition"). Consult literature for the
proper terms.
The very short version is...
Shared declarations:
pthread_mutex_t lock;
pthread_cond_t cond_var;
struct something state_var; // protected by lock, changes signaled by cond_var
Waiter thread:
pthread_mutex_lock(&lock);
// Wait for a change in state_var. We want to wait until predicate_fulfilled()
// returns true.
// Must be a loop for 2 reasons:
// 1. cond_var may be associated with other conditions too
// 2. pthread_cond_wait() can have sporadic wakeups
while (!predicate_fulfilled(&state_var)) {
// This unlocks, waits for cond_var to be signaled, and then locks again.
// The _whole_ point of cond_var is that unlocking and waiting for the
// signal happens atomically.
pthread_cond_wait(&cond_var, &lock);
}
// Here you may react to the state change. The state cannot change
// asynchronously as long as you still hold the lock (and didn't release
// and reacquire it).
// ...
pthread_mutex_unlock(&lock);
Signaler thread:
pthread_mutex_lock(&lock);
// Something changed. Update the shared variable with the new state.
update_state(&state_var);
// Notify that something changed. This will wake up the waiter thread if
// it's blocked in pthread_cond_wait(). If not, nothing happens.
pthread_cond_broadcast(&cond_var);
// Fun fact: good implementations wake up the waiter only when the lock is
// released, to reduce kernel scheduling overhead.
pthread_mutex_unlock(&lock);
Some basic rules:
1. Always access your state under proper locking
2. Always check your predicate before every call to pthread_cond_wait()
(And don't call pthread_cond_wait() if the predicate is fulfilled.)
3. Always call pthread_cond_wait() in a loop
(And only if your predicate failed without releasing the lock..)
4. Always call pthread_cond_broadcast()/_signal() inside of its associated
lock
mpv sometimes violates rule 3, and leaves "retrying" (i.e. looping) to the
caller.
Common pitfalls:
- Thinking that pthread_cond_t is some kind of semaphore, or holds any
application state or the user predicate (it _only_ wakes up threads
that are at the same time blocking on pthread_cond_wait() and friends,
nothing else)
- Changing the predicate, but not updating all pthread_cond_broadcast()/
_signal() calls correctly
- Forgetting that pthread_cond_wait() unlocks the lock (other threads can
and must acquire the lock)
- Holding multiple nested locks while trying to wait (=> deadlock, violates
the lock order anyway)
- Waiting for a predicate correctly, but unlocking/relocking before acting
on it (unlocking allows arbitrary state changes)
- Confusing which lock/condition var. is used to manage a bit of state
Generally available literature probably has better examples and explanations.
Using condition variables the proper way is generally preferred over using more
messy variants of them. (Just saying because on win32, "SetEvent" exists, and
it's inferior to condition variables. Try to avoid the win32 primitives, even if
you're dealing with Windows-only code.)
Threads
-------
Threading should be conservatively used. Normally, mpv code pretends to be
single-threaded, and provides thread-unsafe APIs. Threads are used coarsely,
and if you can avoid messing with threads, you should. For example, VOs and AOs
do not need to deal with threads normally, even though they run on separate
threads. The glue code "isolates" them from any threading issues.

898
config/nushell/config.nu Normal file
View file

@ -0,0 +1,898 @@
# Nushell Config File
#
# version = "0.99.1"
# For more information on defining custom themes, see
# https://www.nushell.sh/book/coloring_and_theming.html
# And here is the theme collection
# https://github.com/nushell/nu_scripts/tree/main/themes
let dark_theme = {
# color for nushell primitives
separator: white
leading_trailing_space_bg: { attr: n } # no fg, no bg, attr none effectively turns this off
header: green_bold
empty: blue
# Closures can be used to choose colors for specific values.
# The value (in this case, a bool) is piped into the closure.
# eg) {|| if $in { 'light_cyan' } else { 'light_gray' } }
bool: light_cyan
int: white
filesize: cyan
duration: white
date: purple
range: white
float: white
string: white
nothing: white
binary: white
cell-path: white
row_index: green_bold
record: white
list: white
block: white
hints: dark_gray
search_result: { bg: red fg: white }
shape_and: purple_bold
shape_binary: purple_bold
shape_block: blue_bold
shape_bool: light_cyan
shape_closure: green_bold
shape_custom: green
shape_datetime: cyan_bold
shape_directory: cyan
shape_external: cyan
shape_externalarg: green_bold
shape_external_resolved: light_yellow_bold
shape_filepath: cyan
shape_flag: blue_bold
shape_float: purple_bold
# shapes are used to change the cli syntax highlighting
shape_garbage: { fg: white bg: red attr: b }
shape_glob_interpolation: cyan_bold
shape_globpattern: cyan_bold
shape_int: purple_bold
shape_internalcall: cyan_bold
shape_keyword: cyan_bold
shape_list: cyan_bold
shape_literal: blue
shape_match_pattern: green
shape_matching_brackets: { attr: u }
shape_nothing: light_cyan
shape_operator: yellow
shape_or: purple_bold
shape_pipe: purple_bold
shape_range: yellow_bold
shape_record: cyan_bold
shape_redirection: purple_bold
shape_signature: green_bold
shape_string: green
shape_string_interpolation: cyan_bold
shape_table: blue_bold
shape_variable: purple
shape_vardecl: purple
shape_raw_string: light_purple
}
let light_theme = {
# color for nushell primitives
separator: dark_gray
leading_trailing_space_bg: { attr: n } # no fg, no bg, attr none effectively turns this off
header: green_bold
empty: blue
# Closures can be used to choose colors for specific values.
# The value (in this case, a bool) is piped into the closure.
# eg) {|| if $in { 'dark_cyan' } else { 'dark_gray' } }
bool: dark_cyan
int: dark_gray
filesize: cyan_bold
duration: dark_gray
date: purple
range: dark_gray
float: dark_gray
string: dark_gray
nothing: dark_gray
binary: dark_gray
cell-path: dark_gray
row_index: green_bold
record: dark_gray
list: dark_gray
block: dark_gray
hints: dark_gray
search_result: { fg: white bg: red }
shape_and: purple_bold
shape_binary: purple_bold
shape_block: blue_bold
shape_bool: light_cyan
shape_closure: green_bold
shape_custom: green
shape_datetime: cyan_bold
shape_directory: cyan
shape_external: cyan
shape_externalarg: green_bold
shape_external_resolved: light_purple_bold
shape_filepath: cyan
shape_flag: blue_bold
shape_float: purple_bold
# shapes are used to change the cli syntax highlighting
shape_garbage: { fg: white bg: red attr: b }
shape_glob_interpolation: cyan_bold
shape_globpattern: cyan_bold
shape_int: purple_bold
shape_internalcall: cyan_bold
shape_keyword: cyan_bold
shape_list: cyan_bold
shape_literal: blue
shape_match_pattern: green
shape_matching_brackets: { attr: u }
shape_nothing: light_cyan
shape_operator: yellow
shape_or: purple_bold
shape_pipe: purple_bold
shape_range: yellow_bold
shape_record: cyan_bold
shape_redirection: purple_bold
shape_signature: green_bold
shape_string: green
shape_string_interpolation: cyan_bold
shape_table: blue_bold
shape_variable: purple
shape_vardecl: purple
shape_raw_string: light_purple
}
# External completer example
# let carapace_completer = {|spans|
# carapace $spans.0 nushell ...$spans | from json
# }
# The default config record. This is where much of your global configuration is setup.
$env.config = {
show_banner: false # true or false to enable or disable the welcome banner at startup
ls: {
use_ls_colors: true # use the LS_COLORS environment variable to colorize output
clickable_links: true # enable or disable clickable links. Your terminal has to support links.
}
rm: {
always_trash: true # always act as if -t was given. Can be overridden with -p
}
table: {
mode: compact # basic, compact, compact_double, light, thin, with_love, rounded, reinforced, heavy, none, other
index_mode: auto # "always" show indexes, "never" show indexes, "auto" = show indexes when a table has "index" column
show_empty: true # show 'empty list' and 'empty record' placeholders for command output
padding: { left: 1, right: 1 } # a left right padding of each column in a table
trim: {
methodology: wrapping # wrapping or truncating
wrapping_try_keep_words: true # A strategy used by the 'wrapping' methodology
truncating_suffix: "..." # A suffix used by the 'truncating' methodology
}
header_on_separator: false # show header text on separator/border line
# abbreviated_row_count: 10 # limit data rows from top and bottom after reaching a set point
}
error_style: "fancy" # "fancy" or "plain" for screen reader-friendly error messages
# Whether an error message should be printed if an error of a certain kind is triggered.
display_errors: {
exit_code: false # assume the external command prints an error message
# Core dump errors are always printed, and SIGPIPE never triggers an error.
# The setting below controls message printing for termination by all other signals.
termination_signal: true
}
# datetime_format determines what a datetime rendered in the shell would look like.
# Behavior without this configuration point will be to "humanize" the datetime display,
# showing something like "a day ago."
datetime_format: {
# normal: '%a, %d %b %Y %H:%M:%S %z' # shows up in displays of variables or other datetime's outside of tables
# table: '%m/%d/%y %I:%M:%S%p' # generally shows up in tabular outputs such as ls. commenting this out will change it to the default human readable datetime format
}
explore: {
status_bar_background: { fg: "#1D1F21", bg: "#C4C9C6" },
command_bar_text: { fg: "#C4C9C6" },
highlight: { fg: "black", bg: "yellow" },
status: {
error: { fg: "white", bg: "red" },
warn: {}
info: {}
},
selected_cell: { bg: light_blue },
}
history: {
max_size: 100_000 # Session has to be reloaded for this to take effect
sync_on_enter: true # Enable to share history between multiple sessions, else you have to close the session to write history to file
file_format: "sqlite" # "sqlite" or "plaintext"
isolation: true # only available with sqlite file_format. true enables history isolation, false disables it. true will allow the history to be isolated to the current session using up/down arrows. false will allow the history to be shared across all sessions.
}
completions: {
case_sensitive: false # set to true to enable case-sensitive completions
quick: true # set this to false to prevent auto-selecting completions when only one remains
partial: true # set this to false to prevent partial filling of the prompt
algorithm: "prefix" # prefix or fuzzy
sort: "smart" # "smart" (alphabetical for prefix matching, fuzzy score for fuzzy matching) or "alphabetical"
external: {
enable: true # set to false to prevent nushell looking into $env.PATH to find more suggestions, `false` recommended for WSL users as this look up may be very slow
max_results: 100 # setting it lower can improve completion performance at the cost of omitting some options
completer: null # check 'carapace_completer' above as an example
}
use_ls_colors: true # set this to true to enable file/path/directory completions using LS_COLORS
}
filesize: {
metric: true # true => KB, MB, GB (ISO standard), false => KiB, MiB, GiB (Windows standard)
format: "auto" # b, kb, kib, mb, mib, gb, gib, tb, tib, pb, pib, eb, eib, auto
}
cursor_shape: {
emacs: line # block, underscore, line, blink_block, blink_underscore, blink_line, inherit to skip setting cursor shape (line is the default)
vi_insert: line # block, underscore, line, blink_block, blink_underscore, blink_line, inherit to skip setting cursor shape (block is the default)
vi_normal: block # block, underscore, line, blink_block, blink_underscore, blink_line, inherit to skip setting cursor shape (underscore is the default)
}
color_config: $dark_theme # if you want a more interesting theme, you can replace the empty record with `$dark_theme`, `$light_theme` or another custom record
footer_mode: 25 # always, never, number_of_rows, auto
float_precision: 2 # the precision for displaying floats in tables
buffer_editor: null # command that will be used to edit the current line buffer with ctrl+o, if unset fallback to $env.EDITOR and $env.VISUAL
use_ansi_coloring: true
bracketed_paste: true # enable bracketed paste, currently useless on windows
edit_mode: vi # emacs, vi
shell_integration: {
# osc2 abbreviates the path if in the home_dir, sets the tab/window title, shows the running command in the tab/window title
osc2: true
# osc7 is a way to communicate the path to the terminal, this is helpful for spawning new tabs in the same directory
osc7: true
# osc8 is also implemented as the deprecated setting ls.show_clickable_links, it shows clickable links in ls output if your terminal supports it. show_clickable_links is deprecated in favor of osc8
osc8: true
# osc9_9 is from ConEmu and is starting to get wider support. It's similar to osc7 in that it communicates the path to the terminal
osc9_9: false
# osc133 is several escapes invented by Final Term which include the supported ones below.
# 133;A - Mark prompt start
# 133;B - Mark prompt end
# 133;C - Mark pre-execution
# 133;D;exit - Mark execution finished with exit code
# This is used to enable terminals to know where the prompt is, the command is, where the command finishes, and where the output of the command is
osc133: true
# osc633 is closely related to osc133 but only exists in visual studio code (vscode) and supports their shell integration features
# 633;A - Mark prompt start
# 633;B - Mark prompt end
# 633;C - Mark pre-execution
# 633;D;exit - Mark execution finished with exit code
# 633;E - Explicitly set the command line with an optional nonce
# 633;P;Cwd=<path> - Mark the current working directory and communicate it to the terminal
# and also helps with the run recent menu in vscode
osc633: true
# reset_application_mode is escape \x1b[?1l and was added to help ssh work better
reset_application_mode: true
}
render_right_prompt_on_last_line: false # true or false to enable or disable right prompt to be rendered on last line of the prompt.
use_kitty_protocol: false # enables keyboard enhancement protocol implemented by kitty console, only if your terminal support this.
highlight_resolved_externals: true # true enables highlighting of external commands in the repl resolved by which.
recursion_limit: 50 # the maximum number of times nushell allows recursion before stopping it
plugins: {} # Per-plugin configuration. See https://www.nushell.sh/contributor-book/plugins.html#configuration.
plugin_gc: {
# Configuration for plugin garbage collection
default: {
enabled: true # true to enable stopping of inactive plugins
stop_after: 10sec # how long to wait after a plugin is inactive to stop it
}
plugins: {
# alternate configuration for specific plugins, by name, for example:
#
# gstat: {
# enabled: false
# }
}
}
hooks: {
pre_prompt: [{ null }] # run before the prompt is shown
pre_execution: [{ null }] # run before the repl input is run
env_change: {
PWD: [{|before, after| null }] # run if the PWD environment is different since the last repl input
}
display_output: "if (term size).columns >= 100 { table -e } else { table }" # run to display the output of a pipeline
command_not_found: { null } # return an error message when a command is not found
}
menus: [
# Configuration for default nushell menus
# Note the lack of source parameter
{
name: completion_menu
only_buffer_difference: false
marker: "| "
type: {
layout: columnar
columns: 4
col_width: 20 # Optional value. If missing all the screen width is used to calculate column width
col_padding: 2
}
style: {
text: green
selected_text: { attr: r }
description_text: yellow
match_text: { attr: u }
selected_match_text: { attr: ur }
}
}
{
name: ide_completion_menu
only_buffer_difference: false
marker: "| "
type: {
layout: ide
min_completion_width: 0,
max_completion_width: 50,
max_completion_height: 10, # will be limited by the available lines in the terminal
padding: 0,
border: true,
cursor_offset: 0,
description_mode: "prefer_right"
min_description_width: 0
max_description_width: 50
max_description_height: 10
description_offset: 1
# If true, the cursor pos will be corrected, so the suggestions match up with the typed text
#
# C:\> str
# str join
# str trim
# str split
correct_cursor_pos: false
}
style: {
text: green
selected_text: { attr: r }
description_text: yellow
match_text: { attr: u }
selected_match_text: { attr: ur }
}
}
{
name: history_menu
only_buffer_difference: true
marker: "? "
type: {
layout: list
page_size: 10
}
style: {
text: green
selected_text: green_reverse
description_text: yellow
}
}
{
name: help_menu
only_buffer_difference: true
marker: "? "
type: {
layout: description
columns: 4
col_width: 20 # Optional value. If missing all the screen width is used to calculate column width
col_padding: 2
selection_rows: 4
description_rows: 10
}
style: {
text: green
selected_text: green_reverse
description_text: yellow
}
}
]
keybindings: [
{
name: completion_menu
modifier: none
keycode: tab
mode: [emacs vi_normal vi_insert]
event: {
until: [
{ send: menu name: completion_menu }
{ send: menunext }
{ edit: complete }
]
}
}
{
name: completion_previous_menu
modifier: shift
keycode: backtab
mode: [emacs, vi_normal, vi_insert]
event: { send: menuprevious }
}
{
name: ide_completion_menu
modifier: control
keycode: space
mode: [emacs vi_normal vi_insert]
event: {
until: [
{ send: menu name: ide_completion_menu }
{ send: menunext }
{ edit: complete }
]
}
}
{
name: history_menu
modifier: control
keycode: char_r
mode: [emacs, vi_insert, vi_normal]
event: { send: menu name: history_menu }
}
{
name: help_menu
modifier: none
keycode: f1
mode: [emacs, vi_insert, vi_normal]
event: { send: menu name: help_menu }
}
{
name: next_page_menu
modifier: control
keycode: char_x
mode: emacs
event: { send: menupagenext }
}
{
name: undo_or_previous_page_menu
modifier: control
keycode: char_z
mode: emacs
event: {
until: [
{ send: menupageprevious }
{ edit: undo }
]
}
}
{
name: escape
modifier: none
keycode: escape
mode: [emacs, vi_normal, vi_insert]
event: { send: esc } # NOTE: does not appear to work
}
{
name: cancel_command
modifier: control
keycode: char_c
mode: [emacs, vi_normal, vi_insert]
event: { send: ctrlc }
}
{
name: quit_shell
modifier: control
keycode: char_d
mode: [emacs, vi_normal, vi_insert]
event: { send: ctrld }
}
{
name: clear_screen
modifier: control
keycode: char_l
mode: [emacs, vi_normal, vi_insert]
event: { send: clearscreen }
}
{
name: search_history
modifier: control
keycode: char_q
mode: [emacs, vi_normal, vi_insert]
event: { send: searchhistory }
}
{
name: open_command_editor
modifier: control
keycode: char_o
mode: [emacs, vi_normal, vi_insert]
event: { send: openeditor }
}
{
name: move_up
modifier: none
keycode: up
mode: [emacs, vi_normal, vi_insert]
event: {
until: [
{ send: menuup }
{ send: up }
]
}
}
{
name: move_down
modifier: none
keycode: down
mode: [emacs, vi_normal, vi_insert]
event: {
until: [
{ send: menudown }
{ send: down }
]
}
}
{
name: move_left
modifier: none
keycode: left
mode: [emacs, vi_normal, vi_insert]
event: {
until: [
{ send: menuleft }
{ send: left }
]
}
}
{
name: move_right_or_take_history_hint
modifier: none
keycode: right
mode: [emacs, vi_normal, vi_insert]
event: {
until: [
{ send: historyhintcomplete }
{ send: menuright }
{ send: right }
]
}
}
{
name: move_one_word_left
modifier: control
keycode: left
mode: [emacs, vi_normal, vi_insert]
event: { edit: movewordleft }
}
{
name: move_one_word_right_or_take_history_hint
modifier: control
keycode: right
mode: [emacs, vi_normal, vi_insert]
event: {
until: [
{ send: historyhintwordcomplete }
{ edit: movewordright }
]
}
}
{
name: move_to_line_start
modifier: none
keycode: home
mode: [emacs, vi_normal, vi_insert]
event: { edit: movetolinestart }
}
{
name: move_to_line_start
modifier: control
keycode: char_a
mode: [emacs, vi_normal, vi_insert]
event: { edit: movetolinestart }
}
{
name: move_to_line_end_or_take_history_hint
modifier: none
keycode: end
mode: [emacs, vi_normal, vi_insert]
event: {
until: [
{ send: historyhintcomplete }
{ edit: movetolineend }
]
}
}
{
name: move_to_line_end_or_take_history_hint
modifier: control
keycode: char_e
mode: [emacs, vi_normal, vi_insert]
event: {
until: [
{ send: historyhintcomplete }
{ edit: movetolineend }
]
}
}
{
name: move_to_line_start
modifier: control
keycode: home
mode: [emacs, vi_normal, vi_insert]
event: { edit: movetolinestart }
}
{
name: move_to_line_end
modifier: control
keycode: end
mode: [emacs, vi_normal, vi_insert]
event: { edit: movetolineend }
}
{
name: move_down
modifier: control
keycode: char_n
mode: [emacs, vi_normal, vi_insert]
event: {
until: [
{ send: menudown }
{ send: down }
]
}
}
{
name: move_up
modifier: control
keycode: char_p
mode: [emacs, vi_normal, vi_insert]
event: {
until: [
{ send: menuup }
{ send: up }
]
}
}
{
name: delete_one_character_backward
modifier: none
keycode: backspace
mode: [emacs, vi_insert]
event: { edit: backspace }
}
{
name: delete_one_word_backward
modifier: control
keycode: backspace
mode: [emacs, vi_insert]
event: { edit: backspaceword }
}
{
name: delete_one_character_forward
modifier: none
keycode: delete
mode: [emacs, vi_insert]
event: { edit: delete }
}
{
name: delete_one_character_forward
modifier: control
keycode: delete
mode: [emacs, vi_insert]
event: { edit: delete }
}
{
name: delete_one_character_backward
modifier: control
keycode: char_h
mode: [emacs, vi_insert]
event: { edit: backspace }
}
{
name: delete_one_word_backward
modifier: control
keycode: char_w
mode: [emacs, vi_insert]
event: { edit: backspaceword }
}
{
name: move_left
modifier: none
keycode: backspace
mode: vi_normal
event: { edit: moveleft }
}
{
name: newline_or_run_command
modifier: none
keycode: enter
mode: emacs
event: { send: enter }
}
{
name: move_left
modifier: control
keycode: char_b
mode: emacs
event: {
until: [
{ send: menuleft }
{ send: left }
]
}
}
{
name: move_right_or_take_history_hint
modifier: control
keycode: char_f
mode: emacs
event: {
until: [
{ send: historyhintcomplete }
{ send: menuright }
{ send: right }
]
}
}
{
name: redo_change
modifier: control
keycode: char_g
mode: emacs
event: { edit: redo }
}
{
name: undo_change
modifier: control
keycode: char_z
mode: emacs
event: { edit: undo }
}
{
name: paste_before
modifier: control
keycode: char_y
mode: emacs
event: { edit: pastecutbufferbefore }
}
{
name: cut_word_left
modifier: control
keycode: char_w
mode: emacs
event: { edit: cutwordleft }
}
{
name: cut_line_to_end
modifier: control
keycode: char_k
mode: emacs
event: { edit: cuttolineend }
}
{
name: cut_line_from_start
modifier: control
keycode: char_u
mode: emacs
event: { edit: cutfromstart }
}
{
name: swap_graphemes
modifier: control
keycode: char_t
mode: emacs
event: { edit: swapgraphemes }
}
{
name: move_one_word_left
modifier: alt
keycode: left
mode: emacs
event: { edit: movewordleft }
}
{
name: move_one_word_right_or_take_history_hint
modifier: alt
keycode: right
mode: emacs
event: {
until: [
{ send: historyhintwordcomplete }
{ edit: movewordright }
]
}
}
{
name: move_one_word_left
modifier: alt
keycode: char_b
mode: emacs
event: { edit: movewordleft }
}
{
name: move_one_word_right_or_take_history_hint
modifier: alt
keycode: char_f
mode: emacs
event: {
until: [
{ send: historyhintwordcomplete }
{ edit: movewordright }
]
}
}
{
name: delete_one_word_forward
modifier: alt
keycode: delete
mode: emacs
event: { edit: deleteword }
}
{
name: delete_one_word_backward
modifier: alt
keycode: backspace
mode: emacs
event: { edit: backspaceword }
}
{
name: delete_one_word_backward
modifier: alt
keycode: char_m
mode: emacs
event: { edit: backspaceword }
}
{
name: cut_word_to_right
modifier: alt
keycode: char_d
mode: emacs
event: { edit: cutwordright }
}
{
name: upper_case_word
modifier: alt
keycode: char_u
mode: emacs
event: { edit: uppercaseword }
}
{
name: lower_case_word
modifier: alt
keycode: char_l
mode: emacs
event: { edit: lowercaseword }
}
{
name: capitalize_char
modifier: alt
keycode: char_c
mode: emacs
event: { edit: capitalizechar }
}
# The following bindings with `*system` events require that Nushell has
# been compiled with the `system-clipboard` feature.
# If you want to use the system clipboard for visual selection or to
# paste directly, uncomment the respective lines and replace the version
# using the internal clipboard.
{
name: copy_selection
modifier: control_shift
keycode: char_c
mode: emacs
event: { edit: copyselection }
# event: { edit: copyselectionsystem }
}
{
name: cut_selection
modifier: control_shift
keycode: char_x
mode: emacs
event: { edit: cutselection }
# event: { edit: cutselectionsystem }
}
# {
# name: paste_system
# modifier: control_shift
# keycode: char_v
# mode: emacs
# event: { edit: pastesystem }
# }
{
name: select_all
modifier: control_shift
keycode: char_a
mode: emacs
event: { edit: selectall }
}
]
}

101
config/nushell/env.nu Normal file
View file

@ -0,0 +1,101 @@
# Nushell Environment Config File
#
# version = "0.99.1"
def create_left_prompt [] {
let dir = match (do --ignore-shell-errors { $env.PWD | path relative-to $nu.home-path }) {
null => $env.PWD
'' => '~'
$relative_pwd => ([~ $relative_pwd] | path join)
}
let path_color = (if (is-admin) { ansi red_bold } else { ansi green_bold })
let separator_color = (if (is-admin) { ansi light_red_bold } else { ansi light_green_bold })
let path_segment = $"($path_color)($dir)(ansi reset)"
$path_segment | str replace --all (char path_sep) $"($separator_color)(char path_sep)($path_color)"
}
def create_right_prompt [] {
# create a right prompt in magenta with green separators and am/pm underlined
let time_segment = ([
(ansi reset)
(ansi magenta)
(date now | format date '%x %X') # try to respect user's locale
] | str join | str replace --regex --all "([/:])" $"(ansi green)${1}(ansi magenta)" |
str replace --regex --all "([AP]M)" $"(ansi magenta_underline)${1}")
let last_exit_code = if ($env.LAST_EXIT_CODE != 0) {([
(ansi rb)
($env.LAST_EXIT_CODE)
] | str join)
} else { "" }
([$last_exit_code, (char space), $time_segment] | str join)
}
# Use nushell functions to define your right and left prompt
$env.PROMPT_COMMAND = {|| create_left_prompt }
# FIXME: This default is not implemented in rust code as of 2023-09-08.
$env.PROMPT_COMMAND_RIGHT = {|| create_right_prompt }
# The prompt indicators are environmental variables that represent
# the state of the prompt
$env.PROMPT_INDICATOR = {|| "> " }
$env.PROMPT_INDICATOR_VI_INSERT = {|| ": " }
$env.PROMPT_INDICATOR_VI_NORMAL = {|| "> " }
$env.PROMPT_MULTILINE_INDICATOR = {|| "::: " }
# If you want previously entered commands to have a different prompt from the usual one,
# you can uncomment one or more of the following lines.
# This can be useful if you have a 2-line prompt and it's taking up a lot of space
# because every command entered takes up 2 lines instead of 1. You can then uncomment
# the line below so that previously entered commands show with a single `🚀`.
# $env.TRANSIENT_PROMPT_COMMAND = {|| "🚀 " }
# $env.TRANSIENT_PROMPT_INDICATOR = {|| "" }
# $env.TRANSIENT_PROMPT_INDICATOR_VI_INSERT = {|| "" }
# $env.TRANSIENT_PROMPT_INDICATOR_VI_NORMAL = {|| "" }
# $env.TRANSIENT_PROMPT_MULTILINE_INDICATOR = {|| "" }
# $env.TRANSIENT_PROMPT_COMMAND_RIGHT = {|| "" }
# Specifies how environment variables are:
# - converted from a string to a value on Nushell startup (from_string)
# - converted from a value back to a string when running external commands (to_string)
# Note: The conversions happen *after* config.nu is loaded
$env.ENV_CONVERSIONS = {
"PATH": {
from_string: { |s| $s | split row (char esep) | path expand --no-symlink }
to_string: { |v| $v | path expand --no-symlink | str join (char esep) }
}
"Path": {
from_string: { |s| $s | split row (char esep) | path expand --no-symlink }
to_string: { |v| $v | path expand --no-symlink | str join (char esep) }
}
}
# Directories to search for scripts when calling source or use
# The default for this is $nu.default-config-dir/scripts
$env.NU_LIB_DIRS = [
($nu.default-config-dir | path join 'scripts') # add <nushell-config-dir>/scripts
($nu.data-dir | path join 'completions') # default home for nushell completions
]
# Directories to search for plugin binaries when calling register
# The default for this is $nu.default-config-dir/plugins
$env.NU_PLUGIN_DIRS = [
($nu.default-config-dir | path join 'plugins') # add <nushell-config-dir>/plugins
]
# To add entries to PATH (on Windows you might use Path), you can use the following pattern:
# $env.PATH = ($env.PATH | split row (char esep) | prepend '/some/path')
# An alternate way to add entries to $env.PATH is to use the custom command `path add`
# which is built into the nushell stdlib:
# use std "path add"
# $env.PATH = ($env.PATH | split row (char esep))
# path add /some/path
# path add ($env.CARGO_HOME | path join "bin")
# path add ($env.HOME | path join ".local" "bin")
# $env.PATH = ($env.PATH | uniq)
# To load from a custom file you can use:
# source ($nu.default-config-dir | path join 'custom.nu')

View file

@ -0,0 +1,9 @@
(directive) @function
(directive_start) @function
(directive_end) @function
(comment) @comment
((parameter) @include (#set! "priority" 110))
((php_only) @include (#set! "priority" 110))
((bracket_start) @function (#set! "priority" 120))
((bracket_end) @function (#set! "priority" 120))
(keyword) @function

View file

@ -0,0 +1,3 @@
((php) @injection.content
(#set! injection.combined)
(#set! injection.language php))

26
config/nvim/init.lua Normal file
View file

@ -0,0 +1,26 @@
-- Loadnoptions before anything
require("aleidk.options")
-- Init PLugins
-- Install package manager https://github.com/folke/lazy.nvim
local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim"
if not vim.loop.fs_stat(lazypath) then
vim.fn.system({
"git",
"clone",
"--filter=blob:none",
"https://github.com/folke/lazy.nvim.git",
"--branch=stable", -- latest stable release
lazypath,
})
end
vim.opt.rtp:prepend(lazypath)
-- Load plugins
require("lazy").setup("aleidk.plugins")
-- Rest of configuratin
require("aleidk.keymaps")
require("aleidk.autocmds")

View file

@ -0,0 +1,80 @@
{
"LuaSnip": { "branch": "master", "commit": "ce0a05ab4e2839e1c48d072c5236cce846a387bc" },
"alpha-nvim": { "branch": "main", "commit": "41283fb402713fc8b327e60907f74e46166f4cfd" },
"auto-session": { "branch": "main", "commit": "4b0728715e674ad9c18f1519127dcaed59f9981b" },
"ccc.nvim": { "branch": "main", "commit": "4fb5abaef2f2e0540fe22d4d74a9841205fff9e4" },
"chezmoi.nvim": { "branch": "main", "commit": "faf61465718424696269b2647077331b3e4605f1" },
"chezmoi.vim": { "branch": "main", "commit": "10f2692791b5e512a2c1bb4dc560b42ca5bf71fd" },
"cmp-buffer": { "branch": "main", "commit": "3022dbc9166796b644a841a02de8dd1cc1d311fa" },
"cmp-cmdline": { "branch": "main", "commit": "d250c63aa13ead745e3a40f61fdd3470efde3923" },
"cmp-conventionalcommits": { "branch": "master", "commit": "a4dfacf0601130b7f8afa7c948d735c27802fb7f" },
"cmp-git": { "branch": "main", "commit": "22116bdffbe68bfc6ca05d52e9f217587cbfea8b" },
"cmp-nvim-lsp": { "branch": "main", "commit": "39e2eda76828d88b773cc27a3f61d2ad782c922d" },
"cmp-path": { "branch": "main", "commit": "91ff86cd9c29299a64f968ebb45846c485725f23" },
"cmp_luasnip": { "branch": "master", "commit": "05a9ab28b53f71d1aece421ef32fee2cb857a843" },
"codecompanion.nvim": { "branch": "main", "commit": "ade8d29c94f6ad3c5b4ccf38517cec13126a6f0d" },
"comment-box.nvim": { "branch": "main", "commit": "06bb771690bc9df0763d14769b779062d8f12bc5" },
"conform.nvim": { "branch": "master", "commit": "0ebe875d9c306f5fc829db38492ffff2a70d8e9d" },
"copilot-cmp": { "branch": "master", "commit": "b6e5286b3d74b04256d0a7e3bd2908eabec34b44" },
"copilot-lualine": { "branch": "main", "commit": "f40450c3e138766026327e7807877ea860618258" },
"copilot.lua": { "branch": "master", "commit": "f8d8d872bb319f640d5177dad5fbf01f7a16d7d0" },
"debugprint.nvim": { "branch": "main", "commit": "8f2a335fb0e6ebf0291a3551e0198363437e3a38" },
"diffview.nvim": { "branch": "main", "commit": "4516612fe98ff56ae0415a259ff6361a89419b0a" },
"dressing.nvim": { "branch": "master", "commit": "6741f1062d3dc6e4755367a7e9b347b553623f04" },
"friendly-snippets": { "branch": "main", "commit": "45a1b96e46efe5fce8af325d4bed45feb9d29d0f" },
"gitsigns.nvim": { "branch": "main", "commit": "e9c4187c3774a46df2d086a66cf3a7e6bea4c432" },
"gopher.nvim": { "branch": "main", "commit": "f55c15ada8e02398000c04a96ef44d986cd01051" },
"grapple.nvim": { "branch": "main", "commit": "7aedc261b05a6c030397c4bc26416efbe746ebf1" },
"hurl.nvim": { "branch": "main", "commit": "d708158dda9a175c0f83cd106ea232301f4317cb" },
"indent-blankline.nvim": { "branch": "master", "commit": "65e20ab94a26d0e14acac5049b8641336819dfc7" },
"lazy.nvim": { "branch": "main", "commit": "7967abe55752aa90532e6bb4bd4663fe27a264cb" },
"lazygit.nvim": { "branch": "main", "commit": "dc56df433bfbf107fee0139e187eb9750878fa84" },
"lualine.nvim": { "branch": "master", "commit": "6a40b530539d2209f7dc0492f3681c8c126647ad" },
"mason-lspconfig.nvim": { "branch": "main", "commit": "37a336b653f8594df75c827ed589f1c91d91ff6c" },
"mason.nvim": { "branch": "main", "commit": "f96a31855fa8aea55599cea412fe611b85a874ed" },
"mini.clue": { "branch": "main", "commit": "08f792869781b4bfdfcaa55eb905b9635c0a243f" },
"mini.comment": { "branch": "main", "commit": "c8406379987c321ecdef9f53e1ca741a55002104" },
"mini.surround": { "branch": "main", "commit": "3cb5b509ad34f2402df4b977be607a614c8c7524" },
"neodev.nvim": { "branch": "main", "commit": "46aa467dca16cf3dfe27098042402066d2ae242d" },
"neogen": { "branch": "main", "commit": "0daffcec249bf42275e322361fe55b89a05ff278" },
"neogit": { "branch": "master", "commit": "a20031fb5d7d12148764764059243135085e5c9b" },
"noice.nvim": { "branch": "main", "commit": "6263b6696811f0b11c88d8d2371134b1cc1762fc" },
"nui.nvim": { "branch": "main", "commit": "61574ce6e60c815b0a0c4b5655b8486ba58089a1" },
"nvim": { "branch": "main", "commit": "7946d1a195c66fed38b3e34f9fa8e0c5a2da0700" },
"nvim-autopairs": { "branch": "master", "commit": "78a4507bb9ffc9b00f11ae0ac48243d00cb9194d" },
"nvim-bqf": { "branch": "main", "commit": "1b24dc6050c34e8cd377b6b4cd6abe40509e0187" },
"nvim-cmp": { "branch": "main", "commit": "a110e12d0b58eefcf5b771f533fc2cf3050680ac" },
"nvim-lint": { "branch": "master", "commit": "efc6fc83f0772283e064c53a8f9fb5645bde0bc0" },
"nvim-lspconfig": { "branch": "master", "commit": "216deb2d1b5fbf24398919228208649bbf5cbadf" },
"nvim-treesitter": { "branch": "master", "commit": "7f4ac678770175cdf0d42c015f4a5b6e18b6cb33" },
"nvim-treesitter-context": { "branch": "master", "commit": "f56a1430f21334868a86eb980b12e0af55690e98" },
"nvim-treesitter-textobjects": { "branch": "master", "commit": "34867c69838078df7d6919b130c0541c0b400c47" },
"nvim-ts-autotag": { "branch": "main", "commit": "323a3e16ed603e2e17b26b1c836d1e86c279f726" },
"nvim-ts-context-commentstring": { "branch": "main", "commit": "6b5f95aa4d24f2c629a74f2c935c702b08dbde62" },
"nvim-web-devicons": { "branch": "master", "commit": "c0cfc1738361b5da1cd0a962dd6f774cc444f856" },
"octo.nvim": { "branch": "master", "commit": "aa5dfa573220a0a511a25ee14ce1570b6c23e56a" },
"overseer.nvim": { "branch": "master", "commit": "15b6249eaf71ebbc8bf0ed279e045f2bc1f28007" },
"plenary.nvim": { "branch": "master", "commit": "a3e3bc82a3f95c5ed0d7201546d5d2c19b20d683" },
"pretty-fold.nvim": { "branch": "master", "commit": "a7d8b424abe0eedf50116c460fbe6dfd5783b1d5" },
"remote-sshfs.nvim": { "branch": "main", "commit": "8f05563150fbd713027471eed56f391b053ba8b8" },
"render-markdown": { "branch": "main", "commit": "123048b428eb85618780fcef9ea9f4d68b5d2508" },
"smart-splits.nvim": { "branch": "master", "commit": "95833675cd92538bf9cded1d2d58d1fc271c5428" },
"telescope-fzf-native.nvim": { "branch": "main", "commit": "cf48d4dfce44e0b9a2e19a008d6ec6ea6f01a83b" },
"telescope.nvim": { "branch": "master", "commit": "a0bbec21143c7bc5f8bb02e0005fa0b982edc026" },
"tfm.nvim": { "branch": "main", "commit": "fb0de2c96bf303216ac5d91ce9bdb7f430030f8b" },
"todo-comments.nvim": { "branch": "main", "commit": "d61567557e2ff5c548c74e96b2d9f8d33e5fcb34" },
"tree-sitter-nu": { "branch": "main", "commit": "7e0f16f608a9e804fae61430ade734f9f849fb80" },
"treesj": { "branch": "main", "commit": "6e8bd008bacd5ad001c3953017c1dca20709e915" },
"trouble.nvim": { "branch": "main", "commit": "03c1fbf518bef683422a3be9643c3da190903488" },
"ts-node-action": { "branch": "master", "commit": "6d3b60754fd87963d70eadaa2f77873b447eac26" },
"twilight.nvim": { "branch": "main", "commit": "2b632c169a4b51b1eba5be90fde22a80c51c990e" },
"typescript-tools.nvim": { "branch": "master", "commit": "5da4d695d66f676eb6ea766b946e86f93baaafe7" },
"undotree": { "branch": "master", "commit": "56c684a805fe948936cda0d1b19505b84ad7e065" },
"vim-dadbod": { "branch": "master", "commit": "7888cb7164d69783d3dce4e0283decd26b82538b" },
"vim-dadbod-completion": { "branch": "master", "commit": "8c9051c1cfc73fcf5bfe9a84db7097e4f7c0180d" },
"vim-dadbod-ui": { "branch": "master", "commit": "f74a31e8c6c5a9dccc63450a09d5cd64a9294330" },
"vim-illuminate": { "branch": "master", "commit": "5eeb7951fc630682c322e88a9bbdae5c224ff0aa" },
"vim-sleuth": { "branch": "master", "commit": "1cc4557420f215d02c4d2645a748a816c220e99b" },
"zen-mode.nvim": { "branch": "main", "commit": "2694c5a2bc4dc26c7a9e74b9e2b812920c90a830" },
"zk-nvim": { "branch": "main", "commit": "dbf4eeab55b08856c9d6b6722dbff39630bb35eb" }
}

View file

@ -0,0 +1,10 @@
-- Highlight on yank
-- See `:help vim.highlight.on_yank()`
local highlight_group = vim.api.nvim_create_augroup("YankHighlight", { clear = true })
vim.api.nvim_create_autocmd("TextYankPost", {
callback = function()
vim.highlight.on_yank()
end,
group = highlight_group,
pattern = "*",
})

View file

@ -0,0 +1,63 @@
return {
icons = {
misc = {
pint = "",
},
dap = {
Stopped = { "󰁕 ", "DiagnosticWarn", "DapStoppedLine" },
Breakpoint = "",
BreakpointCondition = "",
BreakpointRejected = { "", "DiagnosticError" },
LogPoint = ".>",
},
diagnostics = {
Error = "",
Warn = "",
Hint = "",
Info = "",
},
git = {
added = "",
modified = "",
removed = "",
branch = "",
},
kinds = {
Array = "",
Boolean = "",
Class = "",
Color = "",
Constant = "",
Constructor = "",
Copilot = "",
Enum = "",
EnumMember = "",
Event = "",
Field = "",
File = "",
Folder = "",
Function = "",
Interface = "",
Key = "",
Keyword = "",
Method = "",
Module = "",
Namespace = "",
Null = "",
Number = "",
Object = "",
Operator = "",
Package = "",
Property = "",
Reference = "",
Snippet = "",
String = "",
Struct = "",
Text = "",
TypeParameter = "",
Unit = "",
Value = "",
Variable = "",
},
},
}

View file

@ -0,0 +1,77 @@
-- [[ Basic Keymaps ]]
function MAP(mode, l, r, desc)
vim.keymap.set(mode, l, r, { desc = desc, silent = true })
end
function ReloadModule(module)
package.loaded[module] = nil
require(module)
end
local function default(desc)
return {
silent = true,
desc = desc,
}
end
local function fixIndentation()
local indent = 2
vim.opt.tabstop = indent
vim.opt.shiftwidth = indent
vim.opt.softtabstop = indent
vim.cmd("retab")
end
-- Keymaps for better default experience
-- See `:help vim.keymap.set()`
vim.keymap.set({ "n", "v" }, "<Space>", "<Nop>", { silent = true })
-- vim.keymap.set("n", "<C-s>", "<CMD>w<CR>", default("Keep cursor centered while junping"))
-- Remap for dealing with word wrap
vim.keymap.set("n", "k", "v:count == 0 ? 'gk' : 'k'", { expr = true, silent = true })
vim.keymap.set("n", "j", "v:count == 0 ? 'gj' : 'j'", { expr = true, silent = true })
vim.keymap.set("n", "J", "mzJ`z", default("Keep cursor in column while joining lines"))
vim.keymap.set("n", "|", ":vs<CR>", default("Open vsplit"))
vim.keymap.set("n", "°", ":sp<CR>", default("Open split"))
vim.keymap.set("n", "<C-d>", "<C-d>zz", default("Keep cursor centered while junping"))
vim.keymap.set("n", "<C-u>", "<C-u>zz", default("Keep cursor centered while junping"))
vim.keymap.set("n", "n", "nzzzv", default("Keep cursor centered while searching"))
vim.keymap.set("n", "N", "Nzzzv", default("Keep cursor centered while searching"))
vim.keymap.set("n", "Q", "<nop>", {})
vim.keymap.set(
"n",
"<leader>rw",
[[:%s/\<<C-r><C-w>\>/<C-r><C-w>/gI<Left><Left><Left>]],
default("Search and replace current word")
)
-- vim.keymap.set("n", "<leader>rR", ":s/", default("Search and replace inline"))
-- vim.keymap.set("n", "<leader>rr", ":%s/", default("Search and replace globally"))
-- vim.keymap.set("v", "<leader>r", ":s/", default("Search and replace in selection"))
vim.keymap.set("v", "p", [["_dP]], default("Paste without lossing yanked text"))
vim.keymap.set("v", "J", ":m '>+1<CR>gv=gv", default("Move selection down"))
vim.keymap.set("v", "K", ":m '<-2<CR>gv=gv", default("Move selection up"))
vim.keymap.set("n", "<Leader>uI", fixIndentation, default("Fix indentation"))
vim.keymap.set("n", "<Leader>uO", function() ReloadModule('aleidk.options') end,
default("Reload the options configuration"))
vim.keymap.set("n", "<Leader>uh", ":nohl<CR>", default("Remove search highlight"))
vim.keymap.set("t", "<ESC>", "<C-\\><C-n>", default("Exit insert mode on terminal"))
vim.keymap.set("n", "<leader>bc", "<Cmd>bd<CR>", default("Close buffer"))
vim.keymap.set("n", "<leader>bh", "<Cmd>bp<CR>", default("Prev buffer"))
vim.keymap.set("n", "<leader>bl", "<Cmd>bn<CR>", default("Next buffer"))
vim.keymap.set("n", "<leader>bA", "<Cmd>bufdo bd<CR>", default("Close all buffers"))

View file

@ -0,0 +1,76 @@
-- [[ Setting options ]]
-- See `:help vim.o`
-- Set <space> as the leader key
vim.g.mapleader = " "
vim.g.maplocalleader = " "
local opt = vim.opt
-- stylua: ignore
opt.autowrite = true -- Enable auto write
opt.clipboard = "unnamedplus" -- Sync with system clipboard
opt.completeopt = "menu,menuone,noselect"
opt.conceallevel = 2 -- Hide * markup for bold and italic
opt.confirm = true -- Confirm to save changes before exiting modified buffer
opt.cursorline = true -- Enable highlighting of the current line
opt.expandtab = true -- Use spaces instead of tabs
opt.formatoptions = "jcroqlnt" -- tcqj
opt.grepformat = "%f:%l:%c:%m"
opt.grepprg = "rg --vimgrep"
opt.ignorecase = true -- Ignore case
opt.inccommand = "nosplit" -- preview incremental substitute
opt.laststatus = 0
opt.list = true -- Show some invisible characters (tabs...
opt.mouse = "a" -- Enable mouse mode
opt.number = true -- Print line number
opt.pumblend = 10 -- Popup blend
opt.pumheight = 10 -- Maximum number of entries in a popup
opt.relativenumber = true -- Relative line numbers
opt.scrolloff = 15 -- Lines of context
opt.sessionoptions = { "buffers", "curdir", "tabpages", "winsize" }
opt.shiftround = true -- Round indent
opt.shiftwidth = 2 -- Size of an indent
opt.shortmess:append({ W = true, I = true, c = true })
opt.showmode = false -- Dont show mode since we have a statusline
opt.sidescrolloff = 8 -- Columns of context
opt.signcolumn = "yes" -- Always show the signcolumn, otherwise it would shift the text each time
opt.smartcase = true -- Don't ignore case with capitals
opt.smartindent = true -- Insert indents automatically
opt.spelllang = { "en" }
opt.splitbelow = true -- Put new windows below current
opt.splitright = true -- Put new windows right of current
opt.tabstop = 2 -- Number of spaces tabs count for
opt.termguicolors = true -- True color support
opt.timeoutlen = 300
opt.undofile = true
opt.undolevels = 10000
opt.updatetime = 200 -- Save swap file and trigger CursorHold
opt.wildmode = "longest,list:full" -- Command-line completion mode
opt.winminwidth = 5 -- Minimum window width
opt.wrap = false -- Disable line wrap
vim.o.sessionoptions = "blank,buffers,curdir,folds,help,tabpages,winsize,winpos,terminal,localoptions"
vim.filetype.add({
-- Detect and assign filetype based on the extension of the filename
extension = {
mdx = "mdx",
log = "log",
conf = "conf",
env = "dotenv",
},
-- Detect and apply filetypes based on the entire filename
filename = {
[".env"] = "dotenv",
["env"] = "dotenv",
["tsconfig.json"] = "jsonc",
},
-- Detect and apply filetypes based on certain patterns of the filenames
pattern = {
-- INFO: Match filenames like - ".env.example", ".env.local" and so on
["%.env%.[%w_.-]+"] = "dotenv",
[".*%.blade%.php"] = "blade",
[".*%.hurl.*"] = "hurl",
},
})

View file

@ -0,0 +1,78 @@
return {
"olimorris/codecompanion.nvim",
dependencies = {
"nvim-lua/plenary.nvim",
"nvim-treesitter/nvim-treesitter",
{
"zbirenbaum/copilot.lua",
cmd = "Copilot",
event = "InsertEnter",
config = function()
require("copilot").setup({
suggestion = { enabled = false },
panel = { enabled = true, auto_refresh = true },
})
end,
},
"hrsh7th/nvim-cmp", -- Optional: For using slash commands and variables in the chat buffer
"nvim-telescope/telescope.nvim", -- Optional: For using slash commands
{ "stevearc/dressing.nvim", opts = {} }, -- Optional: Improves `vim.ui.select`
},
opts = {
strategies = {
chat = {
adapter = "copilot",
},
inline = {
adapter = "copilot",
},
agent = { adapter = "copilot" },
},
display = {
action_palette = {
prompt = ""
}
}
},
keys = {
{
"<leader>at",
function()
require("codecompanion").toggle()
end,
desc = "Toggle AI chat",
mode = { "n", "v" }
},
{
"<leader>aa",
"<CMD>CodeCompanion<CR>",
desc = "Run an inline prompt",
mode = { "n", "v" }
},
{
"<leader>aA",
function()
require("codecompanion").actions()
end,
desc = "Open AI actions",
mode = { "n", "v" }
},
{
"<leader>av",
function()
require("codecompanion").add()
end,
desc = "Add visual selection to chat",
mode = "v"
},
{
"<leader>ae",
function()
require("codecompanion").prompt("explain")
end,
desc = "Explain code",
mode = "v"
},
}
}

View file

@ -0,0 +1,5 @@
return {
"windwp/nvim-autopairs",
event = "InsertEnter",
opts = {}, -- this is equalent to setup({}) function
}

View file

@ -0,0 +1,34 @@
local function select_or_create(search)
local grapple = require("grapple")
if grapple.exists(search) then
grapple.select(search)
else
grapple.tag()
end
end
return {
"cbochs/grapple.nvim",
dependencies = {
{ "nvim-tree/nvim-web-devicons", lazy = true },
},
lazy = false,
cmd = "Grapple",
keys = {
{ "<leader><leader>a", "<cmd>Grapple toggle<cr>", desc = "Toggle bookmark for current file" },
{ "<leader><leader>D", "<cmd>Grapple reset<cr>", desc = "Delete all bookmarks" },
{ "<leader><leader>t", "<cmd>Grapple toggle_tags<cr>", desc = "Toggle bookmarks window" },
{ "<leader><leader>T", "<cmd>Grapple toggle_scopes<cr>", desc = "Toggle scopes window" },
{ "<leader><leader>n", "<cmd>Grapple cycle forward<cr>", desc = "Next bookmark" },
{ "<leader><leader>N", "<cmd>Grapple cycle backward<cr>", desc = "Prev bookmark" },
{ "<leader><leader>j", function() select_or_create({ index = 1 }) end, desc = "Go or create bookmark 1" },
{ "<leader><leader>k", function() select_or_create({ index = 2 }) end, desc = "Go or create bookmark 2" },
{ "<leader><leader>l", function() select_or_create({ index = 3 }) end, desc = "Go or create bookmark 3" },
{ "<leader><leader>ñ", function() select_or_create({ index = 4 }) end, desc = "Go or create bookmark 4" },
{ "<leader><leader>J", "<cmd>Grapple tag index=1<cr>", desc = "Override bookmark 1" },
{ "<leader><leader>K", "<cmd>Grapple tag index=2<cr>", desc = "Override bookmark 2" },
{ "<leader><leader>L", "<cmd>Grapple tag index=3<cr>", desc = "Override bookmark 3" },
{ "<leader><leader>Ñ", "<cmd>Grapple tag index=4<cr>", desc = "Override bookmark 4" },
},
}

View file

@ -0,0 +1,39 @@
return { -- Change colors.none if not using a transparent background
"catppuccin/nvim",
priority = 1000,
lazy = false,
opts = {
flavour = "macchiato",
transparent_background = true,
integrations = {
cmp = true,
notify = true,
harpoon = false,
mason = true,
neogit = true,
noice = true,
hop = true,
lsp_trouble = true,
indent_blankline = {
enabled = true,
},
},
custom_highlights = function(colors)
return {
-- Fix colors for cmp
Pmenu = { bg = colors.none, blend = 0 },
FloatBorder = { bg = colors.none },
CmpItemMenu = { fg = colors.text, bg = colors.none },
-- dadbod-ui
NotificationInfo = { bg = colors.none, fg = colors.text },
NotificationWarning = { bg = colors.none, fg = colors.yellow },
NotificationError = { bg = colors.none, fg = colors.red },
}
end,
},
config = function(_, opts)
require("catppuccin").setup(opts)
vim.cmd.colorscheme("catppuccin")
end,
}

View file

@ -0,0 +1,49 @@
return {
{
"echasnovski/mini.comment",
version = "*",
event = "VeryLazy",
dependencies = {
{ "nvim-treesitter/nvim-treesitter-context" },
},
opts = {
options = {
custom_commentstring = function()
return require("ts_context_commentstring.internal").calculate_commentstring()
or vim.bo.commentstring
end,
},
},
},
{
"LudoPinelli/comment-box.nvim",
event = "VeryLazy",
config = function()
require("comment-box").setup({
outer_blank_lines = true,
})
local cb = require("comment-box")
-- left aligned fixed size box with left aligned text
MAP({ "n", "v" }, "gcb", cb.lcbox, "Create a comment box")
-- centered adapted box with centered text
MAP({ "n", "v" }, "gcl", cb.llline, "Create a comment line")
end,
},
{
"danymat/neogen",
opts = { snippet_engine = "luasnip" },
dependencies = { "nvim-treesitter/nvim-treesitter" },
version = "*", -- stable releases
keys = {
{
"gcd",
function()
require("neogen").generate()
end,
desc = "Generate comment docstring",
},
},
},
}

View file

@ -0,0 +1,120 @@
---@diagnostic disable: missing-fields
return {
"hrsh7th/nvim-cmp",
version = false, -- last release is way too old
event = "InsertEnter",
dependencies = {
"L3MON4D3/LuaSnip",
"davidsierradz/cmp-conventionalcommits",
"hrsh7th/cmp-buffer",
"hrsh7th/cmp-cmdline",
"hrsh7th/cmp-nvim-lsp",
"hrsh7th/cmp-path",
"petertriho/cmp-git",
"saadparwaiz1/cmp_luasnip",
"windwp/nvim-autopairs",
{
"zbirenbaum/copilot-cmp",
config = function()
require("copilot_cmp").setup()
end
},
},
config = function()
vim.api.nvim_set_hl(0, "CmpGhostText", { link = "Comment", default = true })
local cmp = require("cmp")
local cmp_autopairs = require("nvim-autopairs.completion.cmp")
cmp.event:on("confirm_done", cmp_autopairs.on_confirm_done())
local defaults = require("cmp.config.default")()
local window_opts = {
border = "rounded",
side_padding = 1,
-- fix colors for catppuccin colorscheme
winhighlight = "Normal:Pmenu,FloatBorder:FloatBorder,CursorLine:PmenuSel,Search:None",
}
local opts = {
visible_docs = false,
completion = {
completeopt = "menu,menuone,noinsert",
},
snippet = {
expand = function(args)
require("luasnip").lsp_expand(args.body)
end,
},
mapping = cmp.mapping.preset.insert({
["<C-n>"] = cmp.mapping.select_next_item({ behavior = cmp.SelectBehavior.Insert }),
["<C-p>"] = cmp.mapping.select_prev_item({ behavior = cmp.SelectBehavior.Insert }),
["<C-j>"] = cmp.mapping.select_next_item({ behavior = cmp.SelectBehavior.Insert }),
["<C-k>"] = cmp.mapping.select_prev_item({ behavior = cmp.SelectBehavior.Insert }),
["<C-u>"] = cmp.mapping.scroll_docs(-4),
["<C-d>"] = cmp.mapping.scroll_docs(4),
["<C-o>"] = function()
if cmp.visible_docs() then
cmp.close_docs()
else
cmp.open_docs()
end
end,
["<C-Space>"] = cmp.mapping.complete(),
["<C-e>"] = cmp.mapping.abort(),
["<BR>"] = cmp.mapping.abort(),
["<C-CR>"] = cmp.mapping.confirm({ select = false }), -- Confirm only if selected an item
["<CR>"] = cmp.mapping.confirm({
-- Auto confirms first item
behavior = cmp.ConfirmBehavior.Replace,
select = true,
}),
}),
sources = cmp.config.sources({
{ name = "conventionalcommits" },
{ name = "copilot" },
{ name = "nvim_lsp" },
{ name = "luasnip" },
{ name = "buffer" },
{ name = "path" },
}),
formatting = {
fields = { "kind", "abbr", "menu" },
format = function(_, item)
local icons = require("aleidk.constants").icons.kinds
if icons[item.kind] then
item.kind = icons[item.kind] .. item.kind
end
return item
end,
},
window = {
completion = cmp.config.window.bordered(window_opts),
documentation = cmp.config.window.bordered(window_opts),
},
experimental = {
ghost_text = {
hl_group = "CmpGhostText",
},
},
sorting = {
priority_weight = 2,
comparators = {
require("copilot_cmp.comparators").prioritize,
-- Below is the default comparitor list and order for nvim-cmp
cmp.config.compare.offset,
-- cmp.config.compare.scopes, --this is commented in nvim-cmp too
cmp.config.compare.exact,
cmp.config.compare.score,
cmp.config.compare.recently_used,
cmp.config.compare.locality,
cmp.config.compare.kind,
cmp.config.compare.sort_text,
cmp.config.compare.length,
cmp.config.compare.order,
},
},
}
cmp.setup(opts)
end,
}

View file

@ -0,0 +1,35 @@
return {
"goolord/alpha-nvim",
lazy = false,
opts = function()
local dashboard = require("alpha.themes.dashboard")
dashboard.section.header.val = {
" ████ ███ █████ █████ ",
" ░░███ ░░░ ░░███ ░░███ ",
" ██████ ░███ ██████ ████ ███████ ░███ █████",
" ░░░░░███ ░███ ███░░███░░███ ███░░███ ░███░░███ ",
" ███████ ░███ ░███████ ░███ ░███ ░███ ░██████░ ",
" ███░░███ ░███ ░███░░░ ░███ ░███ ░███ ░███░░███ ",
"░░████████ █████░░██████ █████░░████████ ████ █████",
" ░░░░░░░░ ░░░░░ ░░░░░░ ░░░░░ ░░░░░░░░ ░░░░ ░░░░░ ",
}
dashboard.section.header.opts.hl = "DashboardHeader"
dashboard.section.buttons.val = {
dashboard.button("LDR f f", " Find File ", "<leader>ff"),
dashboard.button("LDR LDR t", " Bookmars", "<leader><leader>t"),
dashboard.button("LDR g g", " Git ", "<leader>gg"),
}
dashboard.section.footer.val =
{ " ", " ", " ", "Nvim loaded " .. require("lazy").stats().count .. " plugins " }
dashboard.section.footer.opts.hl = "DashboardFooter"
dashboard.config.layout[1].val = vim.fn.max({ 2, vim.fn.floor(vim.fn.winheight(0) * 0.2) })
dashboard.config.layout[3].val = 5
dashboard.config.opts.noautocmd = true
return dashboard.opts
end,
}

View file

@ -0,0 +1,44 @@
return {
"kristijanhusak/vim-dadbod-ui",
dependencies = {
{ "tpope/vim-dadbod", lazy = true },
{ "kristijanhusak/vim-dadbod-completion", ft = { "sql", "mysql", "plsql" }, lazy = true },
},
cmd = {
"DBUI",
"DBUIToggle",
"DBUIAddConnection",
"DBUIFindBuffer",
},
keys = {
{ "<Leader>ud", "<CMD>DBUIToggle<CR>", desc = "Toggle DB UI" },
},
init = function()
-- Your DBUI configuration
vim.g.db_ui_use_nerd_fonts = 1
vim.g.db_ui_force_echo_notifications = 1
vim.api.nvim_create_autocmd("FileType", {
pattern = {
"sql",
"mysql",
"plsql",
},
command = [[setlocal omnifunc=vim_dadbod_completion#omni]],
})
vim.api.nvim_create_autocmd("FileType", {
pattern = {
"sql",
"mysql",
"plsql",
},
callback = function()
---@diagnostic disable-next-line: missing-fields
require("cmp").setup.buffer({
sources = { { name = "vim-dadbod-completion" }, { name = "buffer" } },
})
end,
})
end,
}

View file

@ -0,0 +1,7 @@
return {
"andrewferrier/debugprint.nvim",
opts = {},
-- Remove the following line to use development versions,
-- not just the formal releases
version = "*",
}

View file

@ -0,0 +1,10 @@
return {
-- better imputs
"stevearc/dressing.nvim",
opts = {
input = {
-- handle by noice
enabled = false,
},
},
}

View file

@ -0,0 +1,100 @@
return {
{
"nvim-tree/nvim-tree.lua",
enabled = false,
version = "*",
dependencies = {
"nvim-tree/nvim-web-devicons",
},
keys = {
{ "<Leader>e", "<CMD>NvimTreeToggle<CR>", desc = "Open file explorer" },
},
cmd = { "NvimTreeToggle", "Tree" },
config = function()
local tree = require("nvim-tree")
local api = require("nvim-tree.api")
tree.setup({
hijack_unnamed_buffer_when_opening = true,
disable_netrw = false,
hijack_netrw = false, -- handle by telescope browser
hijack_cursor = true, -- cursor at the start of filename
sync_root_with_cwd = true,
respect_buf_cwd = true,
update_focused_file = {
enable = true, -- focus curren file
update_root = true,
},
actions = { open_file = { quit_on_open = true } },
renderer = {
full_name = true, -- show remaining name in floating text
group_empty = true, -- group empty folders
add_trailing = true, -- Trailing slash to folders
highlight_opened_files = "all",
highlight_git = true,
},
view = {
centralize_selection = true, -- center current file on enter
width = 30, -- N° of columns or %
},
on_attach = function(bufnr)
local function opts(desc)
return {
desc = "nvim-tree: " .. desc,
buffer = bufnr,
noremap = true,
silent = true,
nowait = true,
}
end
-- Check defaults here: https://github.com/nvim-tree/nvim-tree.lua/wiki/Migrating-To-on_attach
api.config.mappings.default_on_attach(bufnr)
vim.keymap.set("n", "l", api.node.open.edit, opts("Open"))
vim.keymap.set("n", "o", api.node.open.edit, opts("Open"))
vim.keymap.set("n", "<CR>", api.node.open.edit, opts("Open"))
vim.keymap.set("n", "<2-LeftMouse>", api.node.open.edit, opts("Open"))
vim.keymap.set("n", "s", api.node.open.vertical, opts("Open in vsplit"))
vim.keymap.set("n", "v", api.node.open.horizontal, opts("Open in hsplit"))
vim.keymap.set("n", "t", api.node.open.tab, opts("Open in tab"))
vim.keymap.set("n", "h", api.node.navigate.parent_close, opts("Close dir"))
vim.keymap.set("n", "<BS>", api.node.navigate.parent_close, opts("Close dir"))
vim.keymap.set("n", "i", api.tree.toggle_hidden_filter, opts("Toggle Dotfiles"))
vim.keymap.set("n", "I", api.tree.toggle_gitignore_filter, opts("Toggle Git Ignore"))
end,
})
-- Auto open when a dir is opened
local function open_nvim_tree(data)
-- buffer is a directory
local directory = vim.fn.isdirectory(data.file) == 1
if not directory then
return
end
-- create a new, empty buffer
vim.cmd.enew()
-- wipe the directory buffer
vim.cmd.bw(data.buf)
-- change to the directory
vim.cmd.cd(data.file)
-- open the tree
require("nvim-tree.api").tree.open()
end
vim.api.nvim_create_autocmd({ "VimEnter" }, { callback = open_nvim_tree })
vim.api.nvim_create_user_command("Tree", "NvimTreeToggle", {})
-- bindings
-- disabled to discourage the use of this plugin without disabling it
-- vim.keymap.set("n", "<leader>e", ":NvimTreeToggle<CR>", { desc = "Toggle file tree", silent = true })
-- vim.keymap.set("n", "<C-e>", ":NvimTreeToggle<CR>", { desc = "Toggle file tree", silent = true })
end,
},
}

View file

@ -0,0 +1,66 @@
return {
"rolv-apneseth/tfm.nvim",
lazy = false,
opts = {
-- TFM to use
-- Possible choices: "ranger" | "nnn" | "lf" | "vifm" | "yazi" (default)
file_manager = "yazi",
-- Replace netrw entirely
-- Default: false
replace_netrw = true,
-- Enable creation of commands
-- Default: false
-- Commands:
-- Tfm: selected file(s) will be opened in the current window
-- TfmSplit: selected file(s) will be opened in a horizontal split
-- TfmVsplit: selected file(s) will be opened in a vertical split
-- TfmTabedit: selected file(s) will be opened in a new tab page
enable_cmds = true,
-- Custom keybindings only applied within the TFM buffer
-- Default: {}
keybindings = {
["<ESC>"] = "q",
},
-- Customise UI. The below options are the default
ui = {
border = "rounded",
height = 1,
width = 1,
x = 0.5,
y = 0.5,
},
},
keys = {
{
"<leader>e",
function()
require("tfm").open()
end,
desc = "TFM",
},
{
"<leader>mh",
function()
local tfm = require("tfm")
tfm.open(nil, tfm.OPEN_MODE.split)
end,
desc = "TFM - horizontal split",
},
{
"<leader>mv",
function()
local tfm = require("tfm")
tfm.open(nil, tfm.OPEN_MODE.vsplit)
end,
desc = "TFM - vertical split",
},
{
"<leader>mt",
function()
local tfm = require("tfm")
tfm.open(nil, tfm.OPEN_MODE.tabedit)
end,
desc = "TFM - new tab",
},
},
}

View file

@ -0,0 +1,120 @@
return {
"stevearc/conform.nvim",
event = "VeryLazy",
opts = {
-- log_level = vim.log.levels.DEBUG,
-- See aviable formatters in: https://github.com/stevearc/conform.nvim#formatters
-- Formatters can be installed by mason
formatters_by_ft = {
-- Conform will run multiple formatters sequentially
-- Use a stop_after_first = true to run only the first available formatter
-- Use the "_" filetype to run formatters on filetypes that don't
-- have other formatters configured.
["_"] = { "trim_whitespace" },
blade = { "blade-formatter" },
css = { "prettierd", "prettier" },
go = { "gofumpt", "goimports_reviser", "golines" },
html = { "djlint", "prettierd", stop_after_first = true },
javascript = { "prettierd", "prettier", stop_after_first = true },
javascriptreact = { "prettierd", "prettier", stop_after_first = true },
json = { "prettierd", "prettier", stop_after_first = true },
jsonc = { "prettierd", "prettier", stop_after_first = true },
lua = { "stylua" },
markdown = { "markdownlint" },
nim = { "nimpretty" },
php = { "pint" },
python = { "ruff_format", "ruff_organize_imports" },
scss = { "prettierd", "prettier", stop_after_first = true },
sh = { "shfmt" },
typescript = { "prettierd", "prettier", stop_after_first = true },
typescriptreact = { "prettierd", "prettier", stop_after_first = true },
xml = { "lemminx" },
zsh = { "shfmt" }
},
formatters = {
djlint = {
prepend_args = {
"--format-css",
"--indent-css",
"2",
"--format-js",
"--indent-js",
"2",
"--indent",
"2",
"--preserve-blank-lines",
"--quiet"
}
}
},
format_on_save = function(bufnr)
-- Disable with a global or buffer-local variable
if vim.g.disable_autoformat or vim.b[bufnr].disable_autoformat then
return
end
return { timeout_ms = 2000, lsp_fallback = true }
end,
},
config = function(_, opts)
require("conform").setup(opts)
local function toggleAutoFormat()
-- to make this global, change b to g
if vim.b.disable_autoformat == nil then
vim.b.disable_autoformat = true
print("Autoformat set to: " .. tostring(not vim.b.disable_autoformat))
return
end
vim.b.disable_autoformat = not vim.b.disable_autoformat
print("Autoformat set to: " .. tostring(not vim.b.disable_autoformat))
end
MAP("n", "<leader>uf", toggleAutoFormat, "Toggle auto format")
vim.api.nvim_create_user_command("Fmt", function(args)
local range = nil
if args.count ~= -1 then
local end_line = vim.api.nvim_buf_get_lines(0, args.line2 - 1, args.line2, true)[1]
range = {
start = { args.line1, 0 },
["end"] = { args.line2, end_line:len() },
}
end
local function callback(err, did_edit)
if not did_edit then
vim.notify("The file was not formatted:\n" .. tostring(err), vim.log.levels.ERROR)
return
end
if args.bang then
vim.cmd("w")
end
end
require("conform").format(
{
async = true,
lsp_format = "fallback",
range = range,
formatters = args.fargs
},
callback
)
end, {
range = true,
bang = true,
force = true,
desc = "Format the document",
nargs = '*',
-- complete = function()
-- local formatters = require('conform').formatters_by_ft
--
-- return vim.tbl_keys(formatters)
-- end
})
end,
}

View file

@ -0,0 +1,114 @@
return {
{
"lewis6991/gitsigns.nvim",
event = { "BufReadPre", "BufNewFile" },
opts = {
-- See `:help gitsigns.txt`
signs = {
add = { text = "" },
change = { text = "" },
delete = { text = "" },
topdelete = { text = "" },
changedelete = { text = "" },
untracked = { text = "" },
},
on_attach = function(buffer)
local gs = package.loaded.gitsigns
local function map(mode, l, r, desc)
vim.keymap.set(mode, "<leader>g" .. l, r, { buffer = buffer, desc = desc })
end
-- stylua: ignore start
map("n", "j", gs.next_hunk, "Next Hunk")
map("n", "k", gs.prev_hunk, "Prev Hunk")
map({ "n", "v" }, "s", ":Gitsigns stage_hunk<CR>", "Stage Hunk")
map({ "n", "v" }, "r", ":Gitsigns reset_hunk<CR>", "Reset Hunk")
map("n", "u", gs.undo_stage_hunk, "Undo Stage Hunk")
map("n", "R", gs.reset_buffer, "Reset Buffer")
map("n", "<TAB>", gs.preview_hunk, "Preview Hunk")
map("n", "l", function() gs.blame_line({full = true}) end, "Blame Line")
map("n", "d", gs.diffthis, "Diff This")
end,
},
},
{
"kdheepak/lazygit.nvim",
event = "VeryLazy",
dependencies = {
"nvim-lua/plenary.nvim",
},
keys = {
{ "<leader>gG", ":LazyGit<CR>", desc = "Lazygit" },
},
},
{
"NeogitOrg/neogit",
dependencies = {
"nvim-lua/plenary.nvim", -- required
"nvim-telescope/telescope.nvim", -- optional
"sindrets/diffview.nvim", -- optional
},
config = true,
opts = {
disable_line_numbers = false,
console_timeout = 8000,
graph_style = "unicode",
kind = "tab",
ignored_settings = {
"NeogitPushPopup--force",
"NeogitPullPopup--rebase",
"NeogitCommitPopup--allow-empty",
"NeogitCommitPopup--reuse-message",
"NeogitRevertPopup--no-edit",
},
},
keys = {
{
"<leader>gg",
function()
require("neogit").open()
end,
desc = "Neogit",
},
{
"<leader>gc",
function()
require("neogit").open({ "commit" })
end,
desc = "Commit",
},
{
"<leader>gp",
function()
require("neogit").open({ "pull" })
end,
desc = "Pull",
},
{
"<leader>gP",
function()
require("neogit").open({ "push" })
end,
desc = "Push",
},
},
},
{
"pwntester/octo.nvim",
dependencies = {
"nvim-lua/plenary.nvim",
"nvim-telescope/telescope.nvim",
"nvim-tree/nvim-web-devicons",
},
opts = { enable_builtin = true },
keys = {
{
"<leader>go",
"<CMD>Octo<CR>",
desc = "Octo.nvim",
},
},
},
}

View file

@ -0,0 +1,38 @@
return {
"jellydn/hurl.nvim",
dependencies = {
"MunifTanjim/nui.nvim",
"nvim-lua/plenary.nvim",
"nvim-treesitter/nvim-treesitter"
},
ft = "hurl",
opts = {
-- Show debugging info
debug = false,
-- Show notification on run
show_notification = false,
-- Show response in popup or split
mode = "popup",
-- Default formatter
formatters = {
json = { 'jq' }, -- Make sure you have install jq in your system, e.g: brew install jq
html = {
'prettierd', -- Make sure you have install prettier in your system, e.g: npm install -g prettier
'--parser',
'html',
},
},
env_file = {
'hurl.env',
'.env',
'.env.local',
},
},
keys = {
-- Run API request
{ "<leader>ph", "<cmd>HurlRunnerAt<CR>", desc = "Run HTTP request" },
{ "<leader>pH", "<cmd>HurlRunner<CR>", desc = "Run all HTTP requests" },
-- Run Hurl request in visual mode
{ "<leader>ph", ":HurlRunner<CR>", desc = "Run HTTP requests", mode = "v" },
},
}

View file

@ -0,0 +1,30 @@
return {
-- Add indentation guides even on blank lines
"lukas-reineke/indent-blankline.nvim",
event = { "BufReadPost", "BufNewFile" },
main = "ibl",
opts = {
-- char = "▏",
indent = {
char = "",
tab_char = "",
},
scope = {
enabled = true,
},
exclude = {
filetypes = {
"help",
"alpha",
"dashboard",
"neo-tree",
"Trouble",
"lazy",
"mason",
"notify",
"toggleterm",
"lazyterm",
},
},
},
}

View file

@ -0,0 +1,99 @@
return {
-- Detect tabstop and shiftwidth automatically
"tpope/vim-sleuth",
{ "nvim-tree/nvim-web-devicons", lazy = true },
{
"mbbill/undotree",
config = function()
vim.g.undotree_WindowLayout = 2
vim.g.undotree_ShortIndicators = 1
vim.g.undotree_SetFocusWhenToggle = 1
end,
keys = {
{ "<leader>fu", vim.cmd.UndotreeToggle, desc = "Undo tree" },
},
},
{
-- Highlight word under cursor
"RRethy/vim-illuminate",
event = { "BufReadPost", "BufNewFile" },
opts = { delay = 200 },
config = function(_, opts)
require("illuminate").configure(opts)
end,
},
{
-- Color Picker
"uga-rosa/ccc.nvim",
event = "VeryLazy",
opts = {
auto_enable = true,
lsp = true,
},
keys = {
{ "<leader>uc", "<CMD>CccPick<CR>", desc = "Open Color picker" },
{ "<leader>uC", "<CMD>CccHighlighterToggle<CR>", desc = "Toggle Color highlight" },
},
},
-- Dotfiles management
{
"xvzc/chezmoi.nvim",
dependencies = { "nvim-lua/plenary.nvim", "alker0/chezmoi.vim" },
config = function()
require("chezmoi").setup({
{
edit = {
watch = false,
force = false,
},
notification = {
on_open = true,
on_apply = true,
on_watch = false,
},
telescope = {
select = { "<CR>" },
},
},
})
vim.api.nvim_create_autocmd({ "BufRead", "BufNewFile" }, {
-- INFO: this should be the same as $(chezmoi source-path)
pattern = { os.getenv("HOME") .. "/.local/share/chezmoi/chezmoi/*" },
callback = function()
vim.schedule(require("chezmoi.commands.__edit").watch)
end,
})
local telescope = require("telescope")
telescope.load_extension("chezmoi")
vim.keymap.set("n", "<leader>fz", telescope.extensions.chezmoi.find_files, { desc = "Find dotfile" })
end,
},
{
"pmizio/typescript-tools.nvim",
dependencies = { "nvim-lua/plenary.nvim", "neovim/nvim-lspconfig" },
opts = {
init_options = {
preferences = {
disableSuggestions = true,
},
},
settings = {
-- array of strings("fix_all"|"add_missing_imports"|"remove_unused"|
-- "remove_unused_imports"|"organize_imports") -- or string "all"
-- to include all supported code actions
-- specify commands exposed as code_actions
expose_as_code_action = "all",
},
},
},
{
"olexsmir/gopher.nvim",
ft = "go",
build = function()
vim.cmd([[silent! GoInstallDeps]])
end,
},
}

View file

@ -0,0 +1,85 @@
return {
"echasnovski/mini.clue",
version = "*",
event = "VeryLazy",
config = function()
local miniclue = require("mini.clue")
miniclue.setup({
triggers = {
-- Leader triggers
{ mode = "n", keys = "<Leader>" },
{ mode = "v", keys = "<Leader>" },
{ mode = "x", keys = "<Leader>" },
-- Built-in completion
{ mode = "i", keys = "<C-x>" },
-- `g` key
{ mode = "n", keys = "g" },
{ mode = "x", keys = "g" },
-- Marks
{ mode = "n", keys = "'" },
{ mode = "n", keys = "`" },
{ mode = "x", keys = "'" },
{ mode = "x", keys = "`" },
-- Registers
{ mode = "n", keys = '"' },
{ mode = "x", keys = '"' },
{ mode = "i", keys = "<C-r>" },
{ mode = "c", keys = "<C-r>" },
-- Window commands
{ mode = "n", keys = "<C-w>" },
-- `z` key
{ mode = "n", keys = "z" },
{ mode = "x", keys = "z" },
},
-- Add a "postkeys" value to activate those keys after others
clues = {
miniclue.gen_clues.builtin_completion(),
miniclue.gen_clues.g(),
miniclue.gen_clues.marks(),
miniclue.gen_clues.registers(),
miniclue.gen_clues.windows(),
miniclue.gen_clues.z(),
{ mode = "n", keys = "<Leader><Leader>", desc = "+Bookmarks" },
{ mode = "n", keys = "<Leader><Leader>n", postkeys = "<Leader><Leader>" },
{ mode = "n", keys = "<Leader><Leader>N", postkeys = "<Leader><Leader>" },
{ mode = "n", keys = "<Leader>b", desc = "+Buffers" },
{ mode = "n", keys = "<Leader>bh", postkeys = "<Leader>b" },
{ mode = "n", keys = "<Leader>bl", postkeys = "<Leader>b" },
{ mode = "n", keys = "<Leader>f", desc = "+Find" },
{ mode = "n", keys = "<Leader>g", desc = "+Git" },
{ mode = "n", keys = "<Leader>l", desc = "+LSP" },
{ mode = "n", keys = "<Leader>r", desc = "+Replace" },
{ mode = "n", keys = "<Leader>u", desc = "+UI & Config" },
{ mode = "n", keys = "<Leader>un", desc = "+Noice" },
{ mode = "n", keys = "<Leader>w", desc = "+Workspace" },
{ mode = "n", keys = "<Leader>p", desc = "+Run stuff" },
{ mode = "n", keys = "<Leader>z", desc = "+ZK" },
{ mode = "v", keys = "<Leader>z", desc = "+ZK" },
{ mode = "v", keys = "<Leader>a", desc = "+AI" },
{ mode = "n", keys = "<Leader>a", desc = "+AI" },
{ mode = "n", keys = "g?", desc = "+Print Debug" },
},
-- Clue window settings
window = {
-- Floating window config
config = {
width = "auto",
},
-- Delay before showing clue window
delay = 200,
-- Keys to scroll inside the clue window
scroll_down = "<C-d>",
scroll_up = "<C-u>",
},
})
end,
}

View file

@ -0,0 +1,29 @@
return {
"mfussenegger/nvim-lint",
event = "VeryLazy",
config = function()
local lint = require("lint")
lint.linters.gitlint.stdin = true
lint.linters.gitlint.args = { "--contrib", "contrib-title-conventional-commits", "--msg-filename", "-" }
lint.linters_by_ft = {
javascript = { "eslint_d" },
typescript = { "eslint_d" },
javascriptreact = { "eslint_d" },
typescriptreact = { "eslint_d" },
-- astro = { "eslint_d" },
python = { "ruff" },
sh = { "shellcheck" },
NeogitCommitMessage = { "gitlint" },
gitcommit = { "gitlint" },
markdown = { "markdownlint" },
}
vim.api.nvim_create_autocmd({ "BufWritePost" }, {
callback = function()
require("lint").try_lint()
end,
})
end,
}

View file

@ -0,0 +1,215 @@
return {
-- LSP Configuration & Plugins
"neovim/nvim-lspconfig",
event = { "BufReadPost", "BufNewFile", "BufWritePre" },
dependencies = {
-- Automatically install LSPs to stdpath for neovim
{ "williamboman/mason.nvim" },
"williamboman/mason-lspconfig.nvim",
-- Additional lua configuration, makes nvim stuff amazing!
{ "folke/neodev.nvim", opts = {} },
},
config = function()
-- LSP settings.
local on_attach = function(_, bufnr)
local nmap = function(keys, func, desc)
if desc then
desc = "LSP: " .. desc
end
vim.keymap.set("n", keys, func, { buffer = bufnr, desc = desc })
end
nmap("<leader>lr", vim.lsp.buf.rename, "Rename")
-- stylua: ignore
vim.keymap.set({ "n", "x", "v" }, "<leader>la", vim.lsp.buf.code_action, { buffer = bufnr, desc = "Code Action" })
nmap("<leader>ld", vim.lsp.buf.type_definition, "Go to type definition")
nmap("<leader>lf", function()
vim.lsp.buf.format()
end, "Format")
nmap("gd", vim.lsp.buf.definition, "Go to definition")
nmap("gr", require("telescope.builtin").lsp_references, "Goto References")
nmap("gI", vim.lsp.buf.implementation, "Go to Implementation")
-- See `:help K` for why this keymap
nmap("K", vim.lsp.buf.hover, "Hover Documentation")
-- nmap("<C-k>", vim.lsp.buf.signature_help, "Signature Documentation")
-- Lesser used LSP functionality
nmap("gD", vim.lsp.buf.declaration, "Goto Declaration")
nmap("<leader>lj", vim.diagnostic.goto_next, "Go to next diagnostic")
nmap("<leader>lk", vim.diagnostic.goto_prev, "Go to prev diagnostic")
nmap("<leader>lK", function()
-- execute twice to enter the float inmediatly
vim.diagnostic.open_float()
vim.diagnostic.open_float()
end, "Hover current diagnostic")
-- Create a command `:Format` local to the LSP buffer
vim.api.nvim_buf_create_user_command(bufnr, "Format", function(_)
vim.lsp.buf.format()
end, { desc = "Format current buffer with LSP" })
end
-- Enable the following language servers
-- To see options and cofigurations: https://github.com/neovim/nvim-lspconfig/blob/master/doc/server_configurations.md
local servers = {
astro = {},
bashls = {},
cssls = {},
dockerls = {},
emmet_ls = {
filetypes = {
"astro",
"css",
"eruby",
"html",
"htmldjango",
"javascriptreact",
"less",
"pug",
"sass",
"scss",
"svelte",
"typescriptreact",
"vue",
"htmlangular",
"php",
"blade"
},
},
html = {},
["nil_ls"] = {},
marksman = {},
pyright = {},
phpactor = {},
gopls = {
settings = {
gopls = {
completeUnimported = true,
usePlaceholders = true,
analyses = {
unusedparams = true,
},
},
},
},
ruff = {},
rust_analyzer = {
settings = {
["rust-analyzer"] = {
imports = {
granularity = {
group = "module",
},
prefix = "self",
},
cargo = {
buildScripts = {
enable = true,
},
},
procMacro = {
enable = true,
},
},
},
},
sqlls = {},
yamlls = {},
tsserver = {
init_options = {
preferences = {
disableSuggestions = true,
},
},
},
lua_ls = {
settings = {
Lua = {
runtime = {
-- Tell the language server which version of Lua you're using
-- (most likely LuaJIT in the case of Neovim)
version = "LuaJIT",
},
-- Make the server aware of Neovim runtime files
workspace = {
checkThirdParty = false,
library = {
vim.env.VIMRUNTIME,
-- "${3rd}/luv/library"
-- "${3rd}/busted/library",
},
},
},
},
},
}
-- nvim-cmp supports additional completion capabilities, so broadcast that to servers
local capabilities = vim.lsp.protocol.make_client_capabilities()
capabilities = require("cmp_nvim_lsp").default_capabilities(capabilities)
-- Ensure the servers above are installed
local mason_lspconfig = require("mason-lspconfig")
mason_lspconfig.setup({
ensure_installed = vim.tbl_keys(servers),
automatic_installation = { exclude = { "astro", "phpactor", "gopls", "rust_analyzer", "sqlls" } },
})
mason_lspconfig.setup_handlers({
function(server_name)
local _border = "single"
local default_config = {
capabilities = capabilities,
on_attach = on_attach,
handlers = {
["textDocument/signatureHelp"] = vim.lsp.with(vim.lsp.handlers.signature_help, {
border = _border,
}),
["textDocument/hover"] = vim.lsp.with(vim.lsp.handlers.hover, {
border = _border,
}),
},
}
require("lspconfig")[server_name].setup(
vim.tbl_deep_extend("force", default_config, servers[server_name] or {})
)
end,
})
vim.diagnostic.config({
update_in_insert = false,
underline = true,
float = {
source = true
},
virtual_text = {
severity = vim.diagnostic.severity.ERROR,
source = true,
spacing = -1,
prefix = nil,
format = function(diagnostic)
-- show small error code instead of whole error that probably won't fit in the screen
-- to see the whole error use other keybindings
return tostring(diagnostic.code)
end,
virt_text_hide = true
},
severity_sort = true,
})
-- Customize gutter icons
local signs = require("aleidk.constants").icons.diagnostics
for type, icon in pairs(signs) do
local hl = "DiagnosticSign" .. type
vim.fn.sign_define(hl, { text = icon, texthl = hl, numhl = hl })
end
end,
}

View file

@ -0,0 +1,230 @@
return {
"nvim-lualine/lualine.nvim",
lazy = false,
dependencies = {
"nvim-tree/nvim-web-devicons",
"cbochs/grapple.nvim",
{ 'AndreM222/copilot-lualine' }
},
opts = function()
local icons = require("aleidk.constants").icons
local palete = require("catppuccin.palettes").get_palette "macchiato"
local function diff_source()
local gitsigns = vim.b.gitsigns_status_dict
if gitsigns then
return {
added = gitsigns.added,
modified = gitsigns.changed,
removed = gitsigns.removed,
}
end
end
local function position_scrollbar(str)
local sbar = { "▁▁", "▂▂", "▃▃", "▄▄", "▅▅", "▆▆", "▇▇", "██" }
local curr_line = vim.api.nvim_win_get_cursor(0)[1]
local lines = vim.api.nvim_buf_line_count(0)
local i = math.floor((curr_line - 1) / lines * #sbar) + 1
return str .. " " .. sbar[i]
end
local codecompanion_status = require("lualine.component"):extend()
codecompanion_status.processing = false
codecompanion_status.spinner_index = 1
local spinner_symbols = require("copilot-lualine.spinners").bouncing_bar
-- Initializer
function codecompanion_status:init(options)
codecompanion_status.super.init(self, options)
local group = vim.api.nvim_create_augroup("CodeCompanionHooks", {})
vim.api.nvim_create_autocmd({ "User" }, {
pattern = "CodeCompanionRequest*",
group = group,
callback = function(request)
if request.match == "CodeCompanionRequestStarted" then
self.processing = true
elseif request.match == "CodeCompanionRequestFinished" then
self.processing = false
end
end,
})
end
-- Function that runs every time statusline is updated
function codecompanion_status:update_status()
if self.processing then
self.spinner_index = (self.spinner_index % #spinner_symbols) + 1
return spinner_symbols[self.spinner_index]
else
return nil
end
end
return {
options = {
theme = "catppuccin",
globalstatus = true,
disabled_filetypes = { statusline = { "dashboard", "alpha" } },
component_separators = "",
section_separators = "",
},
sections = {
lualine_a = {
{
"mode",
padding = 0,
fmt = function()
return " "
end,
},
},
lualine_b = {},
lualine_c = {
{ "branch", icon = icons.git.branch },
{
"copilot",
cond = function()
return vim.bo.filetype ~= "codecompanion"
end,
show_colors = true,
symbols = {
status = {
icons = {
enabled = "",
sleep = "", -- auto-trigger disabled
disabled = "",
warning = "",
unknown = ""
},
hl = {
enabled = palete.teal,
sleep = palete.lavender,
disabled = palete.subtext0,
warning = palete.peach,
unknown = palete.red
}
},
spinners = spinner_symbols,
spinner_color = palete.mauve
},
},
{ codecompanion_status },
{
"overseer",
},
{
-- Macro recording status
function()
return require("noice").api.status.mode.get()
end,
cond = function()
return package.loaded["noice"] and require("noice").api.status.mode.has()
end,
},
},
lualine_x = {
{
function()
return require("grapple").statusline()
end,
},
},
lualine_y = {
{ "searchcount" },
{ "location" },
{
"progress",
fmt = position_scrollbar,
separator = " ",
padding = 0,
},
},
lualine_z = {},
},
winbar = {
lualine_b = {
{
"filename",
path = 1,
symbols = {
modified = "", -- Text to show when the buffer is modified
alternate_file = "#", -- Text to show to identify the alternate file
directory = "", -- Text to show when the buffer is a directory
},
},
},
lualine_y = {
{
"diff",
symbols = {
added = icons.git.added,
modified = icons.git.modified,
removed = icons.git.removed,
},
source = diff_source,
},
{
"diagnostics",
symbols = {
error = icons.diagnostics.Error,
warn = icons.diagnostics.Warn,
info = icons.diagnostics.Info,
hint = icons.diagnostics.Hint,
},
},
},
},
inactive_winbar = {
lualine_b = {
{
"filename",
path = 1,
symbols = {
modified = "", -- Text to show when the buffer is modified
alternate_file = "#", -- Text to show to identify the alternate file
directory = "", -- Text to show when the buffer is a directory
},
},
},
lualine_y = {
{
"diff",
symbols = {
added = icons.git.added,
modified = icons.git.modified,
removed = icons.git.removed,
},
source = diff_source,
},
{
"diagnostics",
symbols = {
error = icons.diagnostics.Error,
warn = icons.diagnostics.Warn,
info = icons.diagnostics.Info,
hint = icons.diagnostics.Hint,
},
},
},
},
extensions = {
"neo-tree",
"lazy",
"fugitive",
"fzf",
"man",
"mason",
"nvim-tree",
"quickfix",
"symbols-outline",
"trouble",
},
}
end,
}

View file

@ -0,0 +1,27 @@
return {
"L3MON4D3/LuaSnip",
dependencies = {
"rafamadriz/friendly-snippets",
config = function()
require("luasnip.loaders.from_vscode").lazy_load()
end,
},
opts = {
history = true,
delete_check_events = "TextChanged",
},
-- stylua: ignore
keys = {
{
"<tab>",
function()
return require("luasnip").jumpable(1) and "<Plug>luasnip-jump-next" or "<tab>"
end,
expr = true,
silent = true,
mode = "i",
},
{ "<tab>", function() require("luasnip").jump(1) end, mode = "s" },
{ "<s-tab>", function() require("luasnip").jump(-1) end, mode = { "i", "s" } },
},
}

View file

@ -0,0 +1,44 @@
return {
{
"MeanderingProgrammer/markdown.nvim",
name = "render-markdown", -- Only needed if you have another plugin named markdown.nvim
-- dependencies = { 'nvim-treesitter/nvim-treesitter', 'echasnovski/mini.nvim' }, -- if you use the mini.nvim suite
-- dependencies = { 'nvim-treesitter/nvim-treesitter', 'echasnovski/mini.icons' }, -- if you use standalone mini plugins
dependencies = { "nvim-treesitter/nvim-treesitter", "nvim-tree/nvim-web-devicons" }, -- if you prefer nvim-web-devicons
opts = {
file_types = { 'markdown', 'codecompanion' },
sign = {
enabled = false,
},
},
},
{
"zk-org/zk-nvim",
config = function()
require("zk").setup({
picker = "select",
})
function MAP(mode, l, r, desc)
vim.keymap.set(mode, l, r, { desc = desc, silent = true })
end
MAP("n", "<CR>", "<Cmd>lua vim.lsp.buf.definition()<CR>", "Open the link under cursor")
MAP("n", "<leader>zn", "<Cmd>ZkNew { dir = vim.fn.expand('%:p:h'), title = vim.fn.input('Title: ') }<CR>",
"Create new note")
MAP("v", "<leader>zN",
":'<,'>ZkNewFromContentSelection { dir = vim.fn.expand('%:p:h'), title = vim.fn.input('Title: ') }<CR>",
"Create new note using selection as content")
MAP("n", "<leader>zl", "<Cmd>ZkInsertLink<CR>", "Insert Link into cursor position")
MAP("v", "<leader>zl", ":'<,'>ZkInsertLinkAtSelection<CR>", "Insert Link into selection")
MAP("n", "<leader>zb", "<Cmd>ZkBacklinks<CR>", "Backlinks")
MAP("n", "<leader>zo", "<Cmd>ZkLinks<CR>", "Outlinks")
MAP("n", "<leader>zf", "<Cmd>ZkNotes<CR>", "Find note")
MAP("n", "<leader>zt", "<Cmd>ZkTags<CR>", "Find tags")
end
}
}

View file

@ -0,0 +1,18 @@
return {
"williamboman/mason.nvim",
cmd = "Mason",
keys = { { "<leader>um", "<cmd>Mason<cr>", desc = "Mason" } },
build = ":MasonUpdate",
opts = {
ensure_installed = {
"blue",
"ruff",
"eslint_d",
"markdownlint",
"nimlsp",
"prettierd",
"shellcheck",
"stylua",
},
},
}

View file

@ -0,0 +1,123 @@
return {
"folke/noice.nvim",
event = "VeryLazy",
dependencies = {
-- if you lazy-load any plugin below, make sure to add proper `module="..."` entries
"MunifTanjim/nui.nvim",
},
opts = {
presets = {
bottom_search = true,
-- command_palette = true,
long_message_to_split = true,
inc_rename = true,
},
lsp = {
override = {
["vim.lsp.util.convert_input_to_markdown_lines"] = true,
["vim.lsp.util.stylize_markdown"] = true,
["cmp.entry.get_documentation"] = true,
},
},
routes = {
{
filter = {
event = "msg_show",
any = {
{ find = "%d+L, %d+B" },
{ find = "; after #%d+" },
{ find = "; before #%d+" },
},
},
view = "mini",
},
{
filter = {
event = "msg_show",
kind = "search_count",
},
opts = { skip = true },
},
},
views = {
cmdline_popup = {
position = {
row = 5,
col = "50%",
},
size = {
width = 60,
height = "auto",
},
},
popupmenu = {
relative = "editor",
position = {
row = 8,
col = "50%",
},
size = {
width = 60,
height = 10,
},
border = {
style = "rounded",
padding = { 0, 1 },
},
win_options = {
winhighlight = { Normal = "Normal", FloatBorder = "DiagnosticInfo" },
},
},
notify = {
enabled = false,
},
messages = {
enabled = false,
},
},
},
-- stylua: ignore
keys = {
{
"<S-Enter>",
function() require("noice").redirect(vim.fn.getcmdline()) end,
mode = "c",
desc =
"Redirect Cmdline"
},
{
"<leader>unl",
function() require("noice").cmd("last") end,
desc =
"Noice Last Message"
},
{
"<leader>unh",
function() require("noice").cmd("history") end,
desc =
"Noice History"
},
{ "<leader>una", function() require("noice").cmd("all") end, desc = "Noice All" },
{ "<leader>und", function() require("noice").cmd("dismiss") end, desc = "Dismiss All" },
{
"<c-f>",
function() if not require("noice.lsp").scroll(4) then return "<c-f>" end end,
silent = true,
expr = true,
desc =
"Scroll forward",
mode = {
"i", "n", "s" }
},
{
"<c-b>",
function() if not require("noice.lsp").scroll(-4) then return "<c-b>" end end,
silent = true,
expr = true,
desc =
"Scroll backward",
mode = {
"i", "n", "s" }
},
},
}

View file

@ -0,0 +1,43 @@
return {
enabled = false,
"anuvyklack/pretty-fold.nvim",
opts = {
sections = {
left = {
"+",
function()
return string.rep("-", vim.v.foldlevel)
end,
" ",
"content",
" ",
"number_of_folded_lines",
" ",
function()
return string.rep("-", vim.v.foldlevel)
end,
"+",
},
},
fill_char = " ",
-- Possible values:
-- "delete" : Delete all comment signs from the fold string.
-- "spaces" : Replace all comment signs with equal number of spaces.
-- false : Do nothing with comment signs.
process_comment_signs = "delete",
-- List of patterns that will be removed from content foldtext section.
stop_words = {
"@brief%s*", -- (for C++) Remove '@brief' and all spaces after.
},
matchup_patterns = {
{ "{", "}" },
{ "%(", ")" }, -- % to escape lua pattern char
{ "%[", "]" }, -- % to escape lua pattern char
},
ft_ignore = { "neorg" },
},
}

View file

@ -0,0 +1,89 @@
return {
{
"kevinhwang91/nvim-bqf",
event = "VeryLazy",
dependencies = {},
config = function()
local fn = vim.fn
function _G.qftf(info)
local items
local ret = {}
-- The name of item in list is based on the directory of quickfix window.
-- Change the directory for quickfix window make the name of item shorter.
-- It's a good opportunity to change current directory in quickfixtextfunc :)
--
-- local alterBufnr = fn.bufname('#') -- alternative buffer is the buffer before enter qf window
-- local root = getRootByAlterBufnr(alterBufnr)
-- vim.cmd(('noa lcd %s'):format(fn.fnameescape(root)))
--
if info.quickfix == 1 then
items = fn.getqflist({ id = info.id, items = 0 }).items
else
items = fn.getloclist(info.winid, { id = info.id, items = 0 }).items
end
local limit = 31
local fnameFmt1, fnameFmt2 = "%-" .. limit .. "s", "…%." .. (limit - 1) .. "s"
local validFmt = "%s │%5d:%-3d│%s %s"
for i = info.start_idx, info.end_idx do
local e = items[i]
local fname = ""
local str
if e.valid == 1 then
if e.bufnr > 0 then
fname = fn.bufname(e.bufnr)
if fname == "" then
fname = "[No Name]"
else
fname = fname:gsub("^" .. vim.env.HOME, "~")
end
-- char in fname may occur more than 1 width, ignore this issue in order to keep performance
if #fname <= limit then
fname = fnameFmt1:format(fname)
else
fname = fnameFmt2:format(fname:sub(1 - limit))
end
end
local lnum = e.lnum > 99999 and -1 or e.lnum
local col = e.col > 999 and -1 or e.col
local qtype = e.type == "" and "" or " " .. e.type:sub(1, 1):upper()
str = validFmt:format(fname, lnum, col, qtype, e.text)
else
str = e.text
end
table.insert(ret, str)
end
return ret
end
vim.o.qftf = "{info -> v:lua._G.qftf(info)}"
-- Adapt fzf's delimiter in nvim-bqf
require("bqf").setup({
filter = {
fzf = {
extra_opts = { "--bind", "ctrl-o:toggle-all", "--delimiter", "" },
},
},
})
local toggle_qf = function()
local qf_open = false
for _, win in pairs(vim.fn.getwininfo()) do
if win["quickfix"] == 1 then
qf_open = true
end
end
if qf_open == true then
vim.cmd("cclose")
return
end
if not vim.tbl_isempty(vim.fn.getqflist()) then
vim.cmd("copen")
end
end
MAP("n", "<Leader>fQ", toggle_qf, "Toggle quickfix")
end,
},
}

View file

@ -0,0 +1,8 @@
return {
"nosduco/remote-sshfs.nvim",
dependencies = { "nvim-telescope/telescope.nvim" },
config = function()
require("remote-sshfs").setup({})
require("telescope").load_extension("remote-sshfs")
end,
}

View file

@ -0,0 +1,23 @@
return {
-- sessions
"rmagatti/auto-session",
config = function()
---@diagnostic disable-next-line: missing-fields
require("auto-session").setup({
log_level = "error",
auto_session_suppress_dirs = {
"/",
"~/",
"~/.config/**",
"~/.local/share/chezmoi/",
"~/.local/share/db_ui",
"~/.local/share/db_ui/**",
"~/Downloads",
},
bypass_session_save_file_types = {
"NeogitStatus",
"Lazy",
},
})
end,
}

View file

@ -0,0 +1,65 @@
-- Move to windows with Ctrl and hjkl
-- Resize to windows with Alt and hjkl
-- Tmux aware
return {
"mrjones2014/smart-splits.nvim",
opts = { ignored_filetypes = { "nofile", "quickfix", "qf", "prompt" }, ignored_buftypes = { "nofile" } },
keys = {
{
"<C-h>",
function()
require("smart-splits").move_cursor_left()
end,
desc = "Move to left window",
},
{
"<C-j>",
function()
require("smart-splits").move_cursor_down()
end,
desc = "Move to bottom window",
},
{
"<C-k>",
function()
require("smart-splits").move_cursor_up()
end,
desc = "Move to upper window",
},
{
"<C-l>",
function()
require("smart-splits").move_cursor_right()
end,
desc = "Move to right window",
},
{
"<A-h>",
function()
require("smart-splits").resize_left()
end,
desc = "Move to left window",
},
{
"<A-j>",
function()
require("smart-splits").resize_down()
end,
desc = "Move to bottom window",
},
{
"<A-k>",
function()
require("smart-splits").resize_up()
end,
desc = "Move to upper window",
},
{
"<A-l>",
function()
require("smart-splits").resize_right()
end,
desc = "Move to right window",
},
},
}

View file

@ -0,0 +1,6 @@
return {
"echasnovski/mini.surround",
disabled = true,
version = "*",
opts = {},
}

View file

@ -0,0 +1,145 @@
local function term_get_effective_line_count(bufnr)
local linecount = vim.api.nvim_buf_line_count(bufnr)
local non_blank_lines = linecount
for i = linecount, 1, -1 do
local line = vim.api.nvim_buf_get_lines(bufnr, i - 1, i, true)[1]
non_blank_lines = i
if line ~= "" then
break
end
end
return non_blank_lines
end
-- This is a copy of the original util function of overseer with the change that
-- vim.api.nvim_win_set_cursor(winid, { lnum, 0 }) column is set to 0 so the output is visible
-- the rest is the same
local scroll_to_end = function(winid)
winid = winid or 0
local bufnr = vim.api.nvim_win_get_buf(winid)
local lnum = vim.api.nvim_buf_line_count(bufnr)
local last_line = vim.api.nvim_buf_get_lines(bufnr, -2, -1, true)[1]
-- Hack: terminal buffers add a bunch of empty lines at the end. We need to ignore them so that
-- we don't end up scrolling off the end of the useful output.
local not_much_output = lnum < vim.o.lines + 6
if vim.bo[bufnr].buftype == "terminal" and not_much_output then
lnum = term_get_effective_line_count(bufnr)
last_line = vim.api.nvim_buf_get_lines(bufnr, lnum - 1, lnum, true)[1]
end
local scrolloff = vim.api.nvim_get_option_value("scrolloff", { scope = "local", win = winid })
vim.api.nvim_set_option_value("scrolloff", 0, { scope = "local", win = winid })
vim.api.nvim_win_set_cursor(winid, { lnum, 0 })
vim.api.nvim_set_option_value("scrolloff", scrolloff, { scope = "local", win = winid })
end
local open_split = function(task, horizontal)
local original_window = vim.api.nvim_get_current_win()
if horizontal then
-- horizontal split across all vertical splits
vim.cmd([[botright split]])
else
-- vertical split across all horizontal splits
vim.cmd([[vert botright split]])
end
-- Update tasks buffer options
vim.api.nvim_win_set_buf(0, task:get_bufnr())
vim.api.nvim_set_option_value("number", false, { scope = "local", win = 0 })
vim.api.nvim_set_option_value("relativenumber", false, { scope = "local", win = 0 })
vim.api.nvim_set_option_value("signcolumn", "no", { scope = "local", win = 0 })
scroll_to_end(0)
-- Go back to the original window
vim.api.nvim_set_current_win(original_window)
end
return {
"stevearc/overseer.nvim",
keys = {
{ "<leader>pO", "<CMD>OverseerQuickAction hsplit<CR>", desc = "Open task in a hsplit" },
{
"<leader>pQ",
"<CMD>OverseerQuickAction close win<CR><CMD>OverseerQuickAction dispose<CR>",
desc = "Close and dispose task's windows",
},
{ "<leader>pW", "<CMD>OverseerQuickAction unwatch<CR>", desc = "Unwatch task" },
{ "<leader>pf", "<CMD>OverseerQuickAction open float<CR>", desc = "Open task in a float window" },
{ "<leader>pl", "<CMD>OverseerLoadBundle<CR>", desc = "Load tasks" },
{ "<leader>pm", "<CMD>OverseerTaskAction<CR>", desc = "Manage task" },
{ "<leader>po", "<CMD>OverseerQuickAction vsplit<CR>", desc = "Open task in a vsplit" },
{ "<leader>pp", "<CMD>OverseerRun<CR>", desc = "Run task" },
{ "<leader>pq", "<CMD>OverseerQuickAction close win<CR>", desc = "Close task's windows" },
{ "<leader>ps", "<CMD>OverseerSaveBundle<CR>", desc = "Save tasks" },
{ "<leader>pt", "<CMD>OverseerToggle<CR>", desc = "Toggle tasks list" },
{ "<leader>pw", "<CMD>OverseerQuickAction watch<CR>", desc = "Watch task" },
},
opts = {
actions = {
["hsplit"] = {
desc = "open terminal in a horizontal split",
condition = function(task)
local bufnr = task:get_bufnr()
return bufnr and vim.api.nvim_buf_is_valid(bufnr)
end,
run = function(task)
open_split(task, true)
end,
},
["vsplit"] = {
desc = "open terminal in a vertical split",
condition = function(task)
local bufnr = task:get_bufnr()
return bufnr and vim.api.nvim_buf_is_valid(bufnr)
end,
run = function(task)
open_split(task, false)
end,
},
["close win"] = {
desc = "open terminal in a vertical split",
condition = function(task)
local bufnr = task:get_bufnr()
return bufnr and vim.api.nvim_buf_is_valid(bufnr)
end,
run = function(task)
local buf = task:get_bufnr()
-- iterar sobre todas las windows y ver si la window tiene attach el buf que quiero cerrar
for _, win in ipairs(vim.api.nvim_list_wins()) do
if buf == vim.api.nvim_win_get_buf(win) then
vim.api.nvim_win_close(win, false)
end
end
end,
},
},
task_list = {
direction = "bottom",
bindings = {
["?"] = "ShowHelp",
["g?"] = "ShowHelp",
["<CR>"] = "RunAction",
["<C-e>"] = "Edit",
["o"] = "Open",
["<C-v>"] = "OpenVsplit",
["<C-s>"] = "OpenSplit",
["<C-f>"] = "OpenFloat",
["<C-q>"] = "OpenQuickFix",
["<TAB>"] = "TogglePreview",
["p"] = "TogglePreview",
["<C-l>"] = "IncreaseAllDetail",
["<C-h>"] = "DecreaseAllDetail",
["L"] = "IncreaseDetail",
["H"] = "DecreaseDetail",
["["] = "DecreaseWidth",
["]"] = "IncreaseWidth",
["{"] = "PrevTask",
["}"] = "NextTask",
["<C-u>"] = "ScrollOutputUp",
["<C-d>"] = "ScrollOutputDown",
["q"] = "Close",
["d"] = "<CMD>OverseerQuickAction dispose<CR>",
},
},
},
}

View file

@ -0,0 +1,90 @@
-- Fuzzy Finder (files, lsp, etc)
return {
"nvim-telescope/telescope.nvim",
version = "*",
event = "VeryLazy",
dependencies = {
{ "nvim-lua/plenary.nvim" },
{
-- Blazingly Fast Fuzzy Finder Algorithm for Telescope
"nvim-telescope/telescope-fzf-native.nvim",
build = "make",
cond = function()
return vim.fn.executable("make") == 1
end,
},
},
config = function()
local actions = require("telescope.actions")
local telescope = require("telescope")
local builtin = require("telescope.builtin")
local opts = {
defaults = {
prompt_prefix = "",
selection_caret = "",
layout_strategy = "vertical",
layout_config = { vertical = { height = 0.99, mirror = true, prompt_position = "top" } },
mappings = {
i = {
["<c-u>"] = actions.preview_scrolling_up,
["<c-d>"] = actions.preview_scrolling_down,
["<C-j>"] = actions.move_selection_next,
["<C-k>"] = actions.move_selection_previous,
["<C-s>"] = actions.file_vsplit,
["<C-v>"] = actions.file_split,
["<ESC>"] = actions.close,
["<C-q>"] = actions.send_to_qflist + actions.open_qflist,
["<M-q>"] = actions.send_selected_to_qflist + actions.open_qflist,
["<c-t>"] = function(...)
return require("trouble.providers.telescope").open_with_trouble(...)
end,
["<a-t>"] = function(...)
return require("trouble.providers.telescope").open_selected_with_trouble(...)
end,
},
},
},
}
telescope.setup(opts)
-- Enable telescope fzf native, if installed
pcall(telescope.load_extension, "fzf")
-- Find files
vim.keymap.set(
"n",
"<leader>fe",
":Telescope file_browser path=%:p:h select_buffer=true<CR>",
{ desc = "File Explorer" }
)
vim.keymap.set("n", "<leader>fb", builtin.buffers, { desc = "Find buffers" })
vim.keymap.set("n", "<leader>ff", builtin.find_files, { desc = "Find files" })
vim.keymap.set("n", "<leader>fF", function()
builtin.find_files({ hidden = true, no_ignore = true })
end, { desc = "Find all files" })
-- Search inside files
vim.keymap.set("n", "<leader>fw", builtin.grep_string, { desc = "Find word under cursor" })
vim.keymap.set("n", "<leader>fW", builtin.live_grep, { desc = "Find word (live grep)" })
-- Help
vim.keymap.set("n", "<leader>fc", builtin.command_history, { desc = "Find in commands history" })
vim.keymap.set("n", "<leader>fC", builtin.commands, { desc = "Find a command" })
vim.keymap.set("n", "<leader>fh", builtin.help_tags, { desc = "Find Help" })
vim.keymap.set("n", "<leader>fk", builtin.keymaps, { desc = "Find Keymaps" })
-- Git
vim.keymap.set("n", "<leader>gb", builtin.git_branches, { desc = "Change branch" })
-- Diagnosticos
-- Disabled, handle by trouble
-- vim.keymap.set("n", "<leader>fD", function()
-- builtin.diagnostics({ bufnr = 0 })
-- end, { desc = "Find diagnostics (Telescope)" })
-- vim.keymap.set("n", "<leader>fD", function()
-- builtin.diagnostics({ bufnr = nil })
-- end, { desc = "Find diagnostics in workspace (Telescope)" })
-- vim.keymap.set("n", "<leader>fz", builtin.spell_suggest, { desc = "Find spell suggestion" })
end,
}

View file

@ -0,0 +1,13 @@
return {
"folke/todo-comments.nvim",
cmd = { "TodoTrouble", "TodoTelescope" },
event = { "BufReadPost", "BufNewFile" },
config = true,
-- stylua: ignore
keys = {
{ "]t", function() require("todo-comments").jump_next() end, desc = "Next todo comment" },
{ "[t", function() require("todo-comments").jump_prev() end, desc = "Previous todo comment" },
{ "<leader>ft", "<cmd>TodoTrouble<cr>", desc = "Find todos (Trouble)" },
{ "<leader>fT", "<cmd>TodoTelescope<cr>", desc = "Find todos (Telescope)" },
},
}

View file

@ -0,0 +1,92 @@
return {
-- Highlight, edit, and navigate code
"nvim-treesitter/nvim-treesitter",
event = { "BufReadPost", "BufNewFile", "BufWritePre", "VeryLazy" },
dependencies = {
"nvim-treesitter/nvim-treesitter-textobjects",
"JoosepAlviste/nvim-ts-context-commentstring",
"nvim-treesitter/nvim-treesitter-context",
{ "windwp/nvim-ts-autotag", opts = {} },
{ "nushell/tree-sitter-nu", build = ":TSUpdate nu" },
},
build = ":TSUpdate",
config = function()
---@diagnostic disable-next-line: missing-fields
require("nvim-treesitter.configs").setup({
-- Autoinstall languages that are not installed. Defaults to false (but you can change for yourself!)
auto_install = true,
highlight = { enable = true },
indent = { enable = true },
incremental_selection = {
enable = true,
},
textobjects = {
select = {
enable = true,
lookahead = true, -- Automatically jump forward to textobj, similar to targets.vim
keymaps = {
-- You can use the capture groups defined in textobjects.scm
["aa"] = "@parameter.outer",
["ia"] = "@parameter.inner",
["af"] = "@function.outer",
["if"] = "@function.inner",
["ac"] = "@class.outer",
["ic"] = "@class.inner",
},
},
move = {
enable = true,
set_jumps = true, -- whether to set jumps in the jumplist
goto_next_start = {
["]m"] = "@function.outer",
["]]"] = "@class.outer",
},
goto_next_end = {
["]M"] = "@function.outer",
["]["] = "@class.outer",
},
goto_previous_start = {
["[m"] = "@function.outer",
["[["] = "@class.outer",
},
goto_previous_end = {
["[M"] = "@function.outer",
["[]"] = "@class.outer",
},
},
swap = {
enable = true,
swap_next = {
["<leader>a"] = "@parameter.inner",
},
swap_previous = {
["<leader>A"] = "@parameter.inner",
},
},
},
-- autotag = { enable = true },
})
require('ts_context_commentstring').setup {
enable_autocmd = false,
}
vim.opt.foldmethod = "expr"
vim.opt.foldexpr = "nvim_treesitter#foldexpr()"
-- Uncoment this line to disable auto folding on file open
vim.cmd("set nofoldenable")
-- TODO: remove this when blade treesitter is added to nvim-treesitter repo
-- Also remove the "config/nvim/after/queries/blade" folder.
local parser_config = require("nvim-treesitter.parsers").get_parser_configs()
parser_config.blade = {
install_info = {
url = "https://github.com/EmranMR/tree-sitter-blade",
files = { "src/parser.c" },
branch = "main",
},
filetype = "blade",
}
end,
}

View file

@ -0,0 +1,24 @@
return {
"folke/trouble.nvim",
dependencies = { "nvim-tree/nvim-web-devicons" },
cmd = { "TroubleToggle", "Trouble" },
keys = {
{ "<leader>fq", "<CMD>TroubleToggle<CR>", desc = "Toggle trouble" },
{ "<leader>fd", "<CMD>TroubleToggle workspace_diagnostics<CR>", desc = "Find diagnostics" },
{
"<leader>fD",
"<CMD>TroubleToggle document_diagnostics<CR>",
desc = "Find diagnostics in workspace",
},
},
config = function()
require("trouble").setup({
mode = "document_diagnostics",
action_keys = {
open_split = "s",
open_vsplit = "v",
open_tab = "t",
},
})
end,
}

View file

@ -0,0 +1,23 @@
return {
{
"ckolkey/ts-node-action",
dependencies = { "nvim-treesitter" },
event = "VeryLazy",
config = function()
require("ts-node-action").setup({})
vim.keymap.set({ "n" }, "<leader>lA", require("ts-node-action").node_action, { desc = "Node Action" })
end,
},
{
"Wansmer/treesj",
cmd = { "TSJToggle" },
keys = {
{ "<leader>lm", "<CMD>TSJToggle<CR>", desc = "Toggle treesitter join" },
},
dependencies = { "nvim-treesitter/nvim-treesitter" },
opts = {
use_default_keymaps = true,
},
},
}

View file

@ -0,0 +1,81 @@
return {
"folke/zen-mode.nvim",
dependencies = {
{
"folke/twilight.nvim",
opts = {
-- your configuration comes here
-- or leave it empty to use the default settings
-- refer to the configuration section below
},
},
},
keys = {
{
"<leader>uz",
function()
require("zen-mode").toggle({})
end,
desc = "Toggle zen mode",
},
},
opts = {
window = {
backdrop = 0.95, -- shade the backdrop of the Zen window. Set to 1 to keep the same as Normal
-- height and width can be:
-- * an absolute number of cells when > 1
-- * a percentage of the width / height of the editor when <= 1
-- * a function that returns the width or the height
width = 0.8, -- width of the Zen window
height = 1, -- height of the Zen window
-- by default, no options are changed for the Zen window
-- uncomment any of the options below, or add other vim.wo options you want to apply
options = {
-- signcolumn = "no", -- disable signcolumn
-- number = false, -- disable number column
-- relativenumber = false, -- disable relative numbers
cursorline = false, -- disable cursorline
-- cursorcolumn = false, -- disable cursor column
-- foldcolumn = "0", -- disable fold column
list = false, -- disable whitespace characters
},
},
plugins = {
-- disable some global vim options (vim.o...)
-- comment the lines to not apply the options
options = {
enabled = true,
ruler = true, -- disables the ruler text in the cmd line area
showcmd = false, -- disables the command in the last line of the screen
-- you may turn on/off statusline in zen mode by setting 'laststatus'
-- statusline will be shown only if 'laststatus' == 3
laststatus = 0, -- turn off the statusline in zen mode
},
twilight = { enabled = true }, -- enable to start Twilight when zen mode opens
gitsigns = { enabled = false }, -- disables git signs
tmux = { enabled = true }, -- disables the tmux statusline
-- this will change the font size on kitty when in zen mode
-- to make this work, you need to set the following kitty options:
-- - allow_remote_control socket-only
-- - listen_on unix:/tmp/kitty
kitty = {
enabled = true,
font = "+8", -- font size increment
},
-- this will change the font size on alacritty when in zen mode
-- requires Alacritty Version 0.10.0 or higher
-- uses `alacritty msg` subcommand to change font size
alacritty = {
enabled = true,
font = "14", -- font size
},
-- this will change the font size on wezterm when in zen mode
-- See else also the Plugins/Wezterm section in this projects README
wezterm = {
enabled = true,
-- can be either an absolute font size or the number of incremental steps
font = "+4", -- (10% increase per step)
},
},
},
}

View file

@ -0,0 +1,5 @@
<?php
$config = new PhpCsFixer\Config();
return $config
->setIndent(" ");

2
config/pycodestyle Normal file
View file

@ -0,0 +1,2 @@
[pycodestyle]
max-line-length = 100

View file

@ -0,0 +1,10 @@
#!/usr/bin/env bash
# Wrapper for launching the configuration from lua. This will add the river
# directory to the LUA_PATH global variable so the configuration can be
# splitted into multiple files
config_dir="${XDG_CONFIG_HOME:-$HOME/.config}/river"
export LUA_PATH="$config_dir/?.lua;$config_dir/?/init.lua;$LUA_PATH"
lua "$config_dir"/init.lua

Some files were not shown because too many files have changed in this diff Show more