diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md deleted file mode 100644 index 81d64c4..0000000 --- a/.github/copilot-instructions.md +++ /dev/null @@ -1,25 +0,0 @@ -# Neovim Config - AI Agent Instructions - -**All agent instructions are in `AGENTS.md` at the repository root.** - -This file exists to satisfy GitHub Copilot's convention of looking for instructions in `.github/copilot-instructions.md`. - -## Quick Reference - -- **Primary instructions**: See `AGENTS.md` -- **Decision log**: See `LOG.md` -- **Keymap reference**: See `README.md` - -## Key Rules (Summary) - -1. **Read `AGENTS.md` first** - it contains all coding rules, architecture decisions, and what NOT to reintroduce -2. **Update docs after changes**: - - Decisions → update `LOG.md` - - User-facing behavior and keymaps → update `README.md` -3. **Modern Lua-first**: Use `vim.opt`, `vim.keymap.set`, `vim.api` - avoid Vimscript -4. **LSP (Neovim 0.11+)**: Use `vim.lsp.config()` + `vim.lsp.enable()`, NOT lspconfig `.setup()` -5. **Project config**: Native `exrc` + `secure`, no neoconf plugin -6. **No new plugins** without explicit user approval - -For complete details, workflow requirements, architecture decisions, and troubleshooting, see `AGENTS.md`. - diff --git a/.gitignore b/.gitignore index 96578ca..a1c6b4b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ -.nvimlog -Session.vim -nvim.log +bundle/ +autoload/ +undodir/* +.vimtmp/* +view/* +tmpdir diff --git a/lua/plugins/.gitkeep b/.vimtmp/.gitkeep similarity index 100% rename from lua/plugins/.gitkeep rename to .vimtmp/.gitkeep diff --git a/AGENTS.md b/AGENTS.md deleted file mode 100644 index 1034680..0000000 --- a/AGENTS.md +++ /dev/null @@ -1,70 +0,0 @@ -# AGENTS: Neovim Configuration - -Scope: the entire `~/.config/nvim` repository. - -## Current setup - -This is the active, daily-use Neovim 0.12 configuration. It is Lua-first, -managed with lazy.nvim, and intended to remain small, fast, and maintainable. - -The main workflows are: - -- netrw for tree browsing, previews, and file operations -- Telescope for fuzzy files, grep, buffers, and symbols -- native `vim.lsp.config()` / `vim.lsp.enable()` configuration -- native insert-mode completion and snippets -- Copilot inline suggestions, separate from the completion menu -- Tree-sitter, Conform, nvim-lint, Gitsigns, and nvim-ufo -- native `nvim.undotree` -- project-local `.nvim.lua` files through native `exrc` + `secure` - -`README.md` documents the user-facing workflows and keymaps. `LOG.md` records -architectural decisions. - -## Maintenance rules - -- Prefer Lua APIs such as `vim.opt`, `vim.keymap.set`, and - `vim.api.nvim_create_autocmd`; use Vimscript only when a native integration - requires it. -- Keep non-plugin behavior in focused modules under `lua/`. -- Keep each plugin specification self-contained under `lua/plugins/`. -- Continue using lazy.nvim; do not mix plugin managers without an explicit - decision to migrate. -- Do not add a plugin without explicit user confirmation. -- Keep netrw as the sole file explorer and Telescope as the fuzzy navigator. -- Use Neovim's native completion rather than reintroducing nvim-cmp or LuaSnip. -- Keep Copilot as inline suggestions rather than a completion-menu source. -- Use the modern LSP API; do not restore legacy `lspconfig.setup()` calls or - neoconf. -- Preserve native project-local configuration through `exrc` + `secure`. -- Keep providers for Ruby, Perl, and Node disabled unless an active plugin - requires one. -- Preserve the existing Lua tabline, but do not restore the old Vimscript - tabline/statusline, foldtext, cursorline/column window hacks, CoC, Neo-tree, - motion plugins, or Markdown rendering plugins unless the user explicitly - revisits those decisions. -- Preserve unrelated user changes and keep patches narrowly scoped. - -## Documentation and validation - -- Update `README.md` whenever user-facing behavior or keymaps change. -- Update its configuration section when formatter, linter, or tool resolution - changes. -- Record significant architectural decisions in `LOG.md`. -- After configuration or plugin changes, run at least: - - ```bash - nvim --headless -c 'lua print("Config loads")' -c 'quitall' - ``` - -- For relevant changes, also exercise the affected workflow interactively. - -## History - -This configuration began as a large Vimscript setup with bundled plugins and -was incrementally rebuilt as a modern Lua configuration. The migration covered -lazy.nvim, native LSP and project configuration, native completion and -Undotree, Telescope, a netrw-centered explorer workflow, Tree-sitter, Copilot, -formatting, linting, and the Paper Tonic colorscheme. After sustained daily use -on Neovim 0.12.6, the migration was declared complete on 2026-10-28. The -decision history remains in `LOG.md` and Git history. diff --git a/LOG.md b/LOG.md deleted file mode 100644 index 47f1575..0000000 --- a/LOG.md +++ /dev/null @@ -1,277 +0,0 @@ -# Neovim Rebuild — Decisions & Reference - -Historical migration record and ongoing architectural decision log. - -- Maintenance instructions: `AGENTS.md` -- Active workflows and keymap reference: `README.md` and `:KeymapsGuide` - -## Decisions Log - -Record every decision here with a short rationale. Append new entries; do not rewrite history. - -- 2025-01-13: **Popup borders for visibility**: Added rounded borders to all floating windows to prevent them from blending into the background. Changed `NormalFloat` and `FloatBorder` backgrounds from transparent (`c.NONE`) to `c.bg_ui` (slightly off-white) in colorscheme. Configured LSP handlers for hover and signature help to use `border = "rounded"`. Diagnostics already had borders configured. This provides clear visual separation between popups and main editor content. -- 2025-01-13: **Git files to quickfix**: Added `gg` keymap to send all modified, deleted, and untracked Git files to quickfix list with status indicators. Uses `git status --porcelain` to parse file status (Modified, Deleted, Added, Untracked, etc.) and displays it in the quickfix text column. Implementation in `utils.git_changed_files()`. Complements existing `hq` (Gitsigns hunks to quickfix) with file-level Git status workflow. -- 2025-01-12: **Custom Tabline Function**: Implemented configurable custom tabline to replace Neovim's hardcoded path shortening (e.g., `a/p/file.txt`). Function in `lua/utils.lua` allows controlling: (1) number of full parent directories via `utils.tabline_full_parents` (default: 1), and (2) shortening length via `utils.tabline_shorten_length` (default: 3 characters). Example: with defaults, `/path/to/my/project/src/file.txt` becomes `pat/to/my/project/src/file.txt`. User preference for seeing enough context in shortened paths while keeping tab width manageable. -- 2025-12-06: PHP LSP = `intelephense` (good PHP ecosystem support; integrates includePaths). -- 2025-12-06: Enable Markdown LSP = `marksman` (lightweight, good MD features). -- 2025-12-06: Use legacy `listchars` and `showbreak` values (preserve muscle memory). -- 2025-12-06: No direnv fallback for local config (keep setup simple and repo-driven). -- 2025-12-06: Project-local config = layered JSON `.nvim.json` + `.nvim.local.json` with `.nvimroot` as workspace boundary marker (multi-repo friendly). -- 2025-12-06: Switch to `folke/neoconf.nvim` for project-local configuration (supersedes custom layered JSON loader); use `.neoconf.json` at workspace root. -- 2025-12-06: Use `mason.nvim` + `mason-lspconfig.nvim` to install/manage LSP servers; keep custom lspconfig setup; include `.neoconf.json` in root detection. - - For PHP validation inside this repo: we require `.neoconf.json` to attach `intelephense` to avoid the repo’s `.git` being chosen as the LSP root. -- 2025-12-06: Plugin approval policy — other plugins are allowed, but do not install any plugin not listed without explicit confirmation. -- 2025-12-07: **CRITICAL REGRESSION FIX**: Neovim 0.11+ does NOT support `on_new_config` callback in `vim.lsp.config()`. Project-local settings (`.nvim.lua`) must be loaded via `LspAttach` autocmd instead. The `on_new_config` hook was silently ignored, causing empty settings and breaking goto-definition for external includes. Solution: Use `LspAttach` to load project settings, merge into `client.settings`, and send `workspace/didChangeConfiguration` notification. -- 2025-12-07: Native `exrc` + `.nvim.lua` finalized as project-local config approach (replaces neoconf, which is incompatible with Neovim 0.11+ native LSP API). Security via `vim.opt.secure = true`. -- 2025-12-07: Navigation Phase 4 decisions: - - Skip Neo-tree in favor of netrw for project visualization - - Use Telescope as primary "find file" tool with fuzzy finding - - Add Oil.nvim for file manipulation (rename/move/delete with buffer sync) - - netrw for tree view and preview splits; Oil for operations that would break buffer names - - PHP `gf` enhancement via `includeexpr` for WordPress/PHP path resolution - - **Working directory locked to project root**: Disabled `autochdir`, set `netrw_keepdir = 1`, captured initial cwd in `vim.g.project_root`, configured Telescope to always search from project root regardless of current buffer -- 2026-07-06: **Alternate-buffer netrw skip**: Added a lightweight real-file buffer tracker and mapped ``/`` so alternate-buffer jumps skip netrw explorer buffers when `#` points at netrw. Netrw buffers are also marked unlisted on FileType to reduce their impact on buffer navigation while preserving netrw browsing behavior. Fallback uses explicit `:buffer #` instead of `:normal! ` so regular alternate-file switching still works from the Lua mapping. -- 2026-07-07: **Netrw alternate detection fix**: Real netrw alternate buffers can lose `filetype=netrw` and remain as an unlisted `NetrwTreeListing` buffer. The alternate-buffer skip now detects that buffer name as netrw so `` returns to the previous real file instead of reopening an empty explorer buffer. -- 2025-12-07: Treesitter Phase 5 decisions: - - Focus on core languages: PHP, HTML, JavaScript, TypeScript, CSS, Markdown, Lua, Bash, JSON - - Enable syntax highlighting with performance safeguard (disable for files >100KB) - - Incremental selection: CR to expand, BS to shrink, S-CR for scope expansion - - Textobjects for functions (`af`/`if`), classes (`ac`/`ic`), parameters (`aa`/`ia`), conditionals, loops, comments - - Movement keymaps: `]f`/`[f` for next/prev function, `]c`/`[c` for classes, `]a`/`[a` for parameters - - Parameter swapping: `a`/`A` to swap with next/prev parameter - - Auto-tag for HTML/PHP/JS/React/TS/Vue files (auto-close, auto-rename, close-on-slash) - - Indent disabled initially (experimental); can enable per-filetype if stable -- 2025-12-07: UX/Editing Phase 6 decisions: - - Enable signcolumn=yes (always show for LSP diagnostics, git signs) - - Enable cursorline (highlight current line) - - Enable colorcolumn=80,120 (visual guides at 80 and 120 chars) - - NO cursorcolumn (as per AGENTS.md) - - NO auto-window toggling behavior (keep settings static, no per-window autocmds) - - NO motion plugin (skip leap/flash for simplicity) - - Undotree moved to separate phase (6.8) - - Comment.nvim for commenting (gcc/gc/gbc/gb keymaps) - - nvim-surround for text objects (ys/ds/cs operators) - - nvim-autopairs for auto-closing brackets/quotes with Treesitter and cmp integration - - indent-blankline for visual indent guides with scope highlighting - - nvim-ufo for enhanced folding with Treesitter/LSP providers (zR/zM/K for peek) - - undotree for visual undo history (u to toggle) -- 2025-12-07: Git integration Phase 7: - - Gitsigns with minimal config for signs in gutter (add, change, delete markers) - - Hunk navigation: `]h`/`[h` for next/prev hunk - - Hunk actions: stage, reset, preview - - NO inline blame or advanced features (keep minimal) -- 2025-12-07: Copilot Phase 8: - - Integrated via copilot.lua + copilot-cmp (completion source) - - Auto-trigger suggestions as you type - - Copilot suggestions appear before LSP in completion menu (higher priority) - - Enabled for all filetypes - - No specific Copilot keymaps (use existing cmp keymaps) - - Node.js v22.21.1 confirmed working -- 2025-12-07: Formatting & Linting Phase 9: - - **Philosophy**: Formatters are authoritative; Neovim settings match formatter output - - **Formatters**: prettier (JS/TS/CSS/JSON/MD/HTML), phpcbf (PHP/WordPress), stylua (Lua), black (Python) - - **Linters**: eslint_d (JS/TS), phpcs (PHP/WordPress), markdownlint (Markdown), ruff (Python) - - **Strategy**: Project-local executables first (node_modules/.bin/, vendor/bin/), then Mason, then system PATH - - **WordPress**: phpcs/phpcbf already installed globally; use phpcs.xml or --standard=WordPress - - **Format-on-save**: Enabled by default, toggle with `lt` - - **Manual format**: `lf` (buffer), `lf` (visual range) - - **Linting split**: conform.nvim for formatting, nvim-lint for diagnostics (replaced none-ls after discovering phpcbf preprocessing bug) - - **Python support**: pyright LSP, ruff formatter/linter, treesitter parser (the original black plan was superseded) - - **Per-filetype indentation**: Explicit settings per filetype to match formatters - - PHP: tabs, 2-space display (WordPress standards) - - JS/TS/CSS/JSON/HTML: 2 spaces (Prettier) - - Lua: 2 spaces (common convention) - - Markdown: 2 spaces (Prettier) - - Python: 4 spaces (Black/PEP 8) - - **Global defaults**: 4 spaces (reasonable baseline for other filetypes) -- 2026-01-12: **conform.nvim migration**: - - **Trigger**: none-ls phpcbf builtin had preprocessing bug that added blank lines before formatting - - **Root cause**: none-ls uses LSP protocol for formatters, adds preprocessing step that corrupted input - - **Investigation**: Created debug wrappers, confirmed phpcbf CLI works correctly, traced issue to none-ls preprocessing - - **Solution**: Migrated to conform.nvim (modern, actively maintained, no LSP overhead) - - **Configuration**: Simplified config using conform's built-in formatters, only customized phpcbf for WordPress standard - - **Benefits**: Simpler code, no custom executable resolution needed, proper stdin/tmpfile handling per formatter - - **Removed**: none-ls.lua deleted (was renamed to .disabled during migration) -- 2025-12-07: Kept Behaviors Phase 10: - - **Abbreviations**: Common typo corrections (`adn→and`, `waht→what`, `tehn→then`, `functin→function`, `positin→position`) in dedicated `lua/abbreviations.lua` file for modularity - - **Templates**: Shell script template (template.sh) auto-loaded via BufNewFile autocmd for `*.sh` files - - **Whitespace highlighting**: Already handled via `listchars` in Phase 3.2 (settings.lua) - - **Persistent folds**: Not needed; UFO handles folding without explicit persistence mechanism - - **Persistent undo**: Re-enabled 2025-01-06 via `undofile=true` and `undodir` in settings.lua (preserves undo history across sessions) -- 2025-12-11: Colorscheme Phase 11.2: - - **Color palette extraction**: Extracted all 45 color definitions from original Paper Tonic colorscheme - - **Structure**: Created `lua/paper-tonic-modern/colors.lua` with comprehensive documentation - - **Categories**: Background colors (main, UI, highlights, status), foreground colors (text grays, exceptions), alerts/diagnostics, primary accents (brownish-red), and secondary accents (green/blue/cyan/magenta palettes) - - **Format**: Each color defined as `{hex, 256-color, ansi}` tuple for broad terminal compatibility - - **Philosophy**: Light, paper-like theme with subtle colors for long reading sessions - - **Next steps**: Phase 11.3 will create colorscheme structure and entry point -- 2025-12-11: Colorscheme Phase 11.3: - - **Colorscheme structure**: Created complete modular colorscheme architecture - - **Entry point**: `colors/paper-tonic-modern.lua` properly resets and loads colorscheme - - **Main module**: `lua/paper-tonic-modern/init.lua` with helper functions for setting highlights - - **Helper functions**: `M.highlight()` for single groups, `M.highlight_all()` for batch operations - - **Color conversion**: Smart conversion between gui/cterm/ansi formats - - **Group modules**: Created stub files for editor, syntax, treesitter, semantic, lsp, and plugins - - **Loading order**: Structured to load groups in logical sequence (editor → syntax → treesitter → semantic → lsp → plugins) - - **Validation**: Colorscheme loads successfully, highlights applied correctly - - **Language color consistency**: All documentation updated to reflect that each language maintains its color identity everywhere (PHP=primary, HTML=blue, CSS=green, templates=magenta) -- 2025-12-11: Colorscheme Phase 11.4: - - **Editor highlights**: Comprehensive UI element highlighting (Normal, StatusLine, CursorLine, Visual, Search, Pmenu, Folds, Diffs, Spelling, Messages) - - **Syntax highlights**: Traditional Vim syntax groups (Comment, String, Function, Keyword, Type, etc.) with language-specific overrides - - **Language support**: Added specific highlighting for CSS (green/c2), HTML (blue/c3), Lua, Markdown, JSON, JavaScript/TypeScript, PHP - - **Color verification**: All key groups tested and verified (Normal=#8c8c8c on #ffffff, htmlTag=#005faf, cssClassName=#008700) - - **CSS classes**: Green tones (c2) for CSS syntax elements - - **HTML tags**: Blue tones (c3) for HTML structure - - **PHP syntax**: Primary brownish-red tones for PHP keywords/functions - - **Test file**: Created test-colorscheme.lua for visual verification -- 2025-12-11: Colorscheme Phase 11.5: - - **TreeSitter highlights**: Comprehensive modern `@*` highlight groups implemented - - **Core groups**: @variable, @function, @keyword, @string, @number, @boolean, @comment, @type, @property, @operator, @punctuation - - **Language constructs**: @keyword.function, @keyword.return, @keyword.conditional, @keyword.repeat, @keyword.exception - - **Markup**: @markup.strong, @markup.italic, @markup.heading (1-6), @markup.link, @markup.raw, @markup.list - - **Template languages**: @punctuation.special.twig, @keyword.jinja (magenta c5 for template syntax) - - **Diagnostics**: @diff.plus, @diff.minus, @diff.delta - - **Debug tool**: Added `hi` keymap to show highlight group and resolved colors under cursor - - **Validation**: All TreeSitter groups tested and verified with correct palette colors -- 2025-12-11: Colorscheme Phase 11.6: - - **Language-specific TreeSitter groups**: Enhanced with comprehensive per-language overrides - - **CSS/SCSS**: Properties, variables ($var, --custom), functions, tag selectors (green c2 tones) - - **HTML**: Tags, attributes, delimiters (blue c3 throughout) - - **PHP**: Variables ($var), functions, methods, built-ins ($this, $GLOBALS), properties (primary brownish-red) - - **JavaScript/TypeScript**: Variables, functions, properties, built-ins (this, arguments), JSX/TSX tags (primary + blue for JSX) - - **Lua**: Variables, functions, built-ins (_G, _VERSION), properties (primary) - - **Markdown**: Headings (1-6), links, code blocks, inline code (primary for structure) - - **JSON**: Properties, strings, numbers, booleans (neutral colors) - - **Bash/Shell**: Variables, functions, built-ins, strings (primary) - - **Color consistency verified**: HTML=#005faf (blue), CSS properties=#7c6666 (primary_weak), PHP variables=#7c6666 - - **Test files**: Created test-html.html, test-css.css, test-colors.php for validation -- 2025-12-11: Colorscheme Phase 11.7: - - **Semantic highlighting**: Custom TreeSitter captures for cross-language consistency - - **CSS semantic captures**: @CssClassName (green c2), @CssIdentifier (strong green c2_strong, bold), @cssPseudoClass (bold brownish-red primary_strong - distinguishes from green selectors), @cssPseudoElement (bold brownish-red), @cssNestingSelector (strong green), @CssUniversalSelector - - **CSS properties**: @CssProp (primary_weak), @CssPropertyValue (bold fg), @CssUnit (delimiter) - - **CSS media queries**: @cssMediaFeatureName, @cssMediaQuery, @cssMediaQueryValue - - **HTML attributes**: @ClassNameAttribute, @IdAttribute, @DataAttribute (all fg_weak for attribute names) - - **HTML data attributes**: @DataAttributeValue (Function color) - - **Cross-language consistency**: Critical feature - class="my-class" in HTML uses same color (@CssClassName, green c2) as .my-class in CSS; id="my-id" in HTML uses same color (@CssIdentifier, green c2_strong) as #my-id in CSS - - **Visual benefits**: Easy to visually match selectors between HTML and CSS files; consistent color coding across languages - - **Custom queries**: Leverages existing after/queries/css/highlights.scm and after/queries/html/highlights.scm - - **Priority fix**: Added `(#set! priority 200)` to all custom captures to override built-in captures (@string priority 99, @constant default priority) - - **Technical note**: Custom queries require `;extends` directive and higher priority than built-in captures to work correctly - - **Pseudo-class design**: Uses bold brownish-red (primary_strong) instead of green to distinguish behavioral modifiers (:hover, :focus) from structural selectors (.class, #id) -- 2025-12-11: Colorscheme Phase 11.8: - - **LSP highlights**: Comprehensive diagnostic and UI highlights - - **LSP diagnostics**: Error (red #d70000), Warn (orange #d75f00), Info (blue #8989af), Hint (green #89af89) - - **LSP diagnostic UI**: Underlines (undercurl for errors/warnings), signs, floating windows, virtual text with tinted backgrounds - - **LSP references**: Cyan background gradients - Text (#e0eaff subtle), Read (#d4f0ff medium), Write (#a3e0ff strong) - - **LSP semantic tokens**: Fallback groups linking to TreeSitter equivalents for consistency - - **Telescope highlights**: Neutral base with primary accent for matching, selection, and titles - - **Gitsigns highlights**: Status colors - Add (green), Change (blue), Delete (red); inline diff backgrounds - - **nvim-cmp highlights**: Primary tones for item kinds, bold for match highlighting, italic for menu - - **Oil.nvim highlights**: Bold directories, status colors for permissions (read=green, write=orange, execute=blue), operation colors - - **indent-blankline**: Subtle grays for guides and scope - - **nvim-ufo**: Subtle backgrounds for folds with preview support -- 2025-12-11: Colorscheme Phase 11.9: - - **Plugin configuration updated**: `lua/plugins/colorscheme.lua` loads `paper-tonic-modern` - - **Cleanup**: Moved old `paper-tonic/` directory to `legacy/paper-tonic-original/` - - **Validation**: Full config reload tested - all highlight groups load correctly - - **Colorscheme integration**: Native Neovim colorscheme at `colors/paper-tonic-modern.lua` - - **No overrides needed**: Modern implementation doesn't require separate override file -- 2025-12-12: Added keymap reference documentation (now `README.md`) + `:KeymapsGuide` floating viewer to document every configured keymap (global + plugin-specific) grouped by source file. -- 2025-12-12: nvim-cmp updated to disable auto-selection; confirm requires explicit item selection. -- 2026-10-27: Phase 12 cleanup retired 607 tracked `.vimtmp` backup artifacts and a broken legacy Paper Tonic symlink while preserving the meaningful Vimscript archive. Added an ignore rule for the retired backup directory and corrected the legacy archive index. -- 2026-10-27: Project `.nvim.lua` settings are now read with `vim.secure.read()` before evaluation. This closes the trust bypass caused by manually calling `dofile()` from the LSP attachment callback. -- 2026-10-27: Validation confirmed a clean Neovim 0.11.5 headless launch in approximately 45 ms with 29 configured plugins. Formatter and language-server executables managed by Mason are present in Mason's bin directory; PHP tools and `lua-language-server` are available system-wide. -- 2026-10-27: Repaired `test-diagnostics.lua` so its intentional unreachable-code example remains valid Lua and can be parsed by `lua_ls`. -- 2026-10-27: Live validation confirmed Intelephense attaches in `WORKSPACE_TEST` and receives the trusted external `includePaths`. Conform reports prettier, phpcbf, and stylua available; nvim-lint resolves eslint_d, phpcs, and markdownlint. -- 2026-10-27: Updated `AGENTS.md` status and LSP architecture notes to reflect completed colorscheme work and the current Phase 12 implementation. -- 2026-10-27: Added Conform's built-in `ruff_format` for Python. Ruff was already Mason-managed for diagnostics; this closes a gap where documentation claimed Python formatting but format-on-save had no Python formatter and disabled LSP fallback. -- 2026-10-27: Fixed `` in netrw when no previous real-file buffer has been recorded. Buffer classification now rejects `nil`, non-numeric, and non-positive buffer identifiers before calling Neovim's buffer API, allowing the mapping to fall back safely. -- 2026-10-27: Removed Oil.nvim after workflow evaluation. Netrw is now the sole tree browser and file explorer, preserving the same navigation model on remote systems; Telescope remains dedicated to fuzzy finding. Removed Oil's plugin spec, lockfile entry, keymaps, colorscheme groups, and active documentation. -- 2026-10-27: Planned the next work in two ordered phases. Phase 13 upgrades the standalone Neovim installation from 0.11.5 to stable 0.12.6 using versioned installations, isolated plugin testing, an unchanged initial lockfile, and an immediate rollback path; plugin updates follow only after core compatibility, and Mason tools remain a later step. Phase 14 then adds netrw-only live previews and read-only directory summaries against the validated 0.12 runtime. -- 2026-10-27: Recorded the pre-upgrade rollback baseline: Neovim 0.11.5, 28 active lazy.nvim plugin specs after Oil removal, 32 compiled Treesitter parser binaries, clean headless startup, all active Lua files parsing, and `git diff --check` passing. The standalone 0.11.5 installation remains untouched under `/opt/neovim/nvim-linux-x86_64`. -- 2026-10-28: Installed the verified official Neovim 0.12.6 archive alongside the untouched 0.11.5 installation at `/opt/neovim/nvim-0.12.6`. Initial interactive startup with the existing configuration succeeded. Removed redundant `vim.lsp.with()` wrappers for hover and signature-help borders after 0.12 reported their deprecation; the shared `vim.lsp.util.open_floating_preview` override already applies the same border on both 0.11 and 0.12. Clean headless startup then passed with the existing locked plugins under both binaries. -- 2026-10-28: The 0.12 health review exposed overlapping LSP activation: mason-lspconfig v2 automatically enabled every installed server while `lsp.lua` explicitly configured and enabled the selected set. Disabled mason-lspconfig automatic activation, removed its obsolete `automatic_installation` option, and aligned it with nvim-lspconfig's buffer events. This prevents unintended activation of installed tools such as StyLua's LSP mode and leaves `lsp.lua` as the single activation authority. -- 2026-10-28: Live Intelephense attachment passed under both Neovim 0.11.5 and 0.12.6 after the LSP activation cleanup. The test also exposed the deprecated function-style `client.notify(...)` call in the project-settings callback; changed it to `client:notify(...)`, which works on both supported versions. -- 2026-10-28: Replaced the remaining `vim.loop.fs_stat` calls with `vim.uv.fs_stat` and migrated `[d`/`]d` from deprecated diagnostic navigation functions to `vim.diagnostic.jump({ count = -1/1 })`. Both APIs remain compatible with the rollback runtime, Neovim 0.11.5. -- 2026-10-28: Validated Neovim 0.12 project configuration using a disposable nested workspace and isolated trust database. With `exrc` and `secure` enabled through a normal XDG config, a trusted parent `.nvim.lua` executed exactly once and `vim.secure.read()` returned its contents. The live Intelephense test separately confirmed that the repository's project-local settings loader still receives trusted settings from the client's root. -- 2026-10-28: Validated the netrw workflow on Neovim 0.12.6. The default runtime wrapper automatically loads bundled netrw v184 from its optional package, so adding a configuration-level `packadd netrw` would be redundant and would complicate 0.11 rollback compatibility. `:Explore` opened the configured tree view, `p` created a real preview window, and `` returned from the explorer to the source file. -- 2026-10-28: Kept `mbbill/undotree` after checking Neovim 0.12's built-in alternative. The native `nvim.undotree` package is optional and remains unloaded; it exposes `:Undotree`, whereas the configured plugin's `:UndotreeToggle` command, focused panel, and diff layout still open successfully under 0.12.6. There is no active command or runtime conflict. -- 2026-10-28: Completed the configuration-level Neovim 0.12 breaking-change audit. Diagnostic jump behavior passed under both 0.11.5 and 0.12.6, and a loaded-plugin `vim.deprecated` scan now reports only `copilot-cmp`'s upstream `client.is_stopped` call. That plugin warning is safe on 0.12 but remains a tracked compatibility concern before Neovim 0.13. -- 2026-10-28: Final Phase 13.3 smoke tests passed: both 0.11.5 and 0.12.6 start with the updated configuration, 0.12 attaches Intelephense with project settings, `git diff --check` is clean, and the measured 0.12 headless startup reached `NVIM STARTED` in approximately 43 ms with the existing locked plugins. -- 2026-10-28: Updated plugins in an isolated Neovim 0.12 worktree and XDG environment. The candidate passed automated loading checks for LSP, completion, Telescope/fzf, Mason integration, formatting, linting, Gitsigns, indent guides, autopairs, surround, UFO, Undotree, and PHP/HTML/CSS/JavaScript Tree-sitter parsers and custom queries. Copilot's new native language-server download completed in isolation and the client authenticated successfully. Mason-managed tools were not updated. -- 2026-10-28: Kept `nvim-treesitter` and `nvim-treesitter-textobjects` on their frozen `master` branches. Their rewritten `main` branches remove the `nvim-treesitter.configs` API used by this configuration and therefore require a separate migration; explicit branch pins prevent an ordinary plugin sync from crossing that boundary. Migrated the updated nvim-surround v4 configuration to its unchanged default mappings by removing the retired `opts.keymaps` field. -- 2026-10-28: Disabled lazy.nvim's LuaRocks integration because no configured plugin requires LuaRocks. This removes the irrelevant missing-hererocks health error without adding a system dependency. Candidate health otherwise reports only optional missing language runtimes, the pending inline-Copilot migration, and the `copilot-cmp` deprecation that will disappear with that migration. -- 2026-10-28: Adopted the isolated candidate's reviewed plugin lockfile and compatibility adjustments into the main worktree. Production plugin directories remain unchanged until the 0.12 activation step, preserving the working 0.11 rollback environment. -- 2026-10-28: Chose the post-activation native-feature direction for 0.12. Keep lazy.nvim because the configuration still benefits from its event/command loading, dependency ordering, and build hooks; do not mix the runtime upgrade with an experimental `vim.pack` migration. After activating 0.12, replace `mbbill/undotree` with the native optional package and trial native insert-mode/LSP completion plus built-in snippets. Copilot will use inline suggestions with a separate accept key rather than appearing in the completion popup; remove the cmp stack only after interactive language and editing validation. -- 2026-10-28: Activated Neovim 0.12.6 with the user-level selector `~/.local/bin/nvim`, which precedes the older `/opt` PATH entry. The root-owned `/opt/neovim` directory could not be reorganized without an interactive sudo password, so 0.11.5 remains intact at `/opt/neovim/nvim-linux-x86_64/bin/nvim`; rollback is `ln -sfn /opt/neovim/nvim-linux-x86_64/bin/nvim ~/.local/bin/nvim`. -- 2026-10-28: Implemented the 0.12 native editing trial. Native `nvim.undotree` now owns `u`; native autocomplete combines LSP omnifunc results and bounded buffer sources after a 150 ms delay, requires explicit selection, accepts with ``, and uses built-in snippet tabstops. Copilot now supplies separate inline ghost text accepted with `` and hides while the completion popup is visible. Removed the nvim-cmp, cmp source, LuaSnip, copilot-cmp, and external Undotree specs, integrations, lock entries, and highlight groups. -- 2026-10-28: Refined native completion after the PTY smoke test showed buffer words sorting ahead of a valid PHP method. LSP-attached buffers now autocomplete exclusively from the LSP omnifunc; `` remains the explicit current-buffer word workflow, and non-LSP buffers retain bounded automatic word completion. This makes the first selectable language result predictable without losing native fallback completion. -- 2026-10-28: Added narrow 0.12 guards around the new `autocomplete` option, source match limits, and optional native Undotree package. The retained 0.11.5 binary can therefore still start the configuration for emergency rollback, although native autocomplete and Undotree are intentionally unavailable until the selector is returned to 0.12.6. -- 2026-10-28: Final smoke testing found that loading `nvim.undotree` before lazy.nvim setup left its command registered but removed its Lua module path. Moved `packadd nvim.undotree` after lazy.nvim finalizes `runtimepath`. The same test showed nvim-ts-autotag attaching to Markdown despite the intended filetype restriction; global autotag actions are now disabled and explicitly enabled only for HTML/PHP/JS/TS/Vue tag-bearing filetypes. -- 2026-10-28: Active-runtime validation passed through the normal `nvim` selector: native Undotree opens, netrw and Telescope load, PHP native completion offers and accepts `greetExternal()` with snippet syntax, Copilot's inline client is authenticated, Markdown no longer runs autotag, and HTML autotag exits Insert mode without errors. `vim.deprecated` is clean. Remaining health warnings are optional missing language runtimes and the harmless unknown `markdown.mdx` filetype hint. -- 2026-10-28: Marked `neovim-migration-guide.md` as historical planning input. Its original Neo-tree, cmp, and plugin assumptions are retained for provenance but no longer compete with the active architecture documents. -- 2026-10-28: User normal-use checks passed for the 0.12 native completion, snippet, autopairs, and inline Copilot workflow, closing the Phase 13.9 settling gate. Began Phase 14 with the confirmed netrw-only model: `p` starts previewing, cursor movement updates an existing preview, directories show read-only immediate-child summaries, and leaving netrw closes the preview. -- 2026-10-28: Revalidated bundled netrw v184. Its documented `netrw#Call()` bridge exposes `NetrwGetWord`, `NetrwTreePath`, `NetrwBrowseChgDir`, and `NetrwPreview`. In tree view, `NetrwTreePath` returns the selected directory path or the selected file's parent, allowing local paths to be resolved without parsing indentation or mutating netrw's expand/collapse state. Remote URI targets will retain native fallback behavior. -- 2026-10-28: Implemented Phase 14's plugin-free netrw preview extension in `lua/netrw-preview.lua`. Pressing `p` previews files through netrw's native machinery or shows a read-only immediate-child directory summary; while that preview window exists, a 90 ms buffer-local cursor debounce replaces it with the current selection. Manual `:pclose` stops updates, and leaving or wiping the explorer releases its preview and timer. Directory summaries are local-filesystem only, mirror netrw's active hide pattern, cap output at 200 entries, and never traverse symbolic links; remote URI schemes fall back to netrw's native preview path. -- 2026-10-28: Automated Phase 14 checks passed for file/directory transitions, manual close and reopen, all four file-open actions, tree expansion and collapse, rapid cursor movement, spaces, Unicode, symlinks, empty and unreadable directories, and the 200-entry cap. A PTY-backed launch on a directory confirmed Neovim 0.12 enters the configured netrw tree, so no special `filetype=directory` handling is required. Separate-tab, deleted-entry, and real SSH checks remain as interactive validation. -- 2026-10-28: An isolated lifecycle rerun exposed netrw's focus hop into an existing preview window while replacing a directory summary through its native preview function. The extension now explicitly restores the netrw window after that call, preserving tree-focused `j`/`k` navigation. Leave cleanup waits 20 ms before checking the settled current window and ignores callbacks raised while the native preview call is active, then closes only after a real explorer exit. The transient re-entrancy guard is not preview-mode state, and the cleanup timer is released when the netrw buffer is wiped. -- 2026-10-28: Fixed a reproducible Neovim 0.12 Tree-sitter race during rapid cross-language netrw previews. Native `:pedit` unloads the previous preview buffer while its asynchronous parser may still be running, producing `TSNode:range()` errors. Preview-only file buffers are now kept loaded but unlisted for the rest of the Neovim session, with Tree-sitter highlighting suspended in favor of Vim syntax; avoiding parser detachment is necessary because delayed unloading reproduces the same race. Pre-existing buffer state is preserved, while entering a previewed file for real editing restores listed-buffer behavior and Tree-sitter immediately. An 80-step Markdown/Lua/JSON preview stress test, edit restoration check, retained-buffer check, and pre-existing-buffer check all pass. -- 2026-10-28: Disabled diagnostic rendering in netrw file preview buffers. The preview metadata records each buffer's prior diagnostic state and restores it when the file is opened for editing, keeping ephemeral previews quiet without overriding buffers where diagnostics were already disabled. -- 2026-10-28: Made netrw file previews intentionally plain after CSS and HTML exposed residual colour. The remaining decoration was Vim regex syntax plus indent-blankline extmarks, not diagnostics or Tree-sitter. Preview buffers now clear `syntax` and disable their buffer-local indent guides, then restore both recorded states on real edit. -- 2026-10-28: Added buffer-local netrw `` / `` mappings to scroll the current preview with native `` / `` behavior while focus remains in the tree. The mappings accept Vim counts and quietly do nothing when no preview exists. -- 2026-10-28: Hardened preview scrolling after an interactive over-scroll surfaced a window-local error that did not reproduce headlessly. The temporary preview-window call is now protected, so stale-window and boundary failures are treated like native top/bottom clamping instead of reaching the command line. -- 2026-10-28: Excluded netrw from automatic session persistence after `:mksession` serialized its generated `NetrwTreeListing` name and restored an empty explorer buffer. Before the existing exit-time save, preview windows and netrw windows are removed; a netrw-only tab is dropped, while the sole remaining netrw window is replaced with an ordinary file buffer or a blank fallback. Netrw is intentionally not rebuilt on load. -- 2026-10-28: Changed the enhanced netrw `p` mapping into a true toggle. With no preview it opens the selected file or directory and begins live cursor updates; with an existing preview it closes that window and stops updates, matching manual `:pclose` behavior. -- 2026-10-28: Declared the migration complete after sustained daily use of the modern Lua configuration. Interactive navigation, language tooling, native completion, Copilot, formatting, linting, and the enhanced netrw workflow are considered validated. Real SSH URI previews and use of stock netrw without this configuration remain optional portability checks, not release gates. This decision also ends the requirement to retain migration-only archives and fixtures in the live repository; their removal will be handled as a separate, explicit cleanup. -- 2026-10-28: Replaced the migration-era `AGENTS.md` with a concise maintenance guide for the established configuration. Removed completed phase tracking, obsolete validation-workspace instructions, resolved issue notes, and the target-tree description; retained current architectural guardrails, documentation expectations, a smoke-test command, and a short history note. -- 2026-10-28: Retired the completed migration's legacy configuration, vendored plugin archive, UltiSnips collection, validation workspaces, root test assets, superseded planning documents, and phase labels in active Lua comments. Git history now provides the historical archive. Persistent undo storage moved from the configuration repository to `stdpath('state')/undo`; the active README, architectural log, lockfile, colorscheme, spell data, and templates remain. -- 2026-10-28: Diagnosed the Tree-sitter `TSNode:range()` failure as the known incompatibility between Neovim 0.12 and nvim-treesitter's locked legacy `master` branch. Migrated nvim-treesitter and nvim-treesitter-textobjects to their rewritten `main` branches: native Neovim highlighting and incremental selection replace the old modules, textobjects use explicit mappings, indentation uses the new plugin expression when a query exists, and autotag retains its direct supported setup. Installed the verified official Tree-sitter CLI 0.26.9 binary in `~/.local/bin` after the system package required interactive sudo and Cargo compilation required unavailable libclang. Reinstalled all configured parsers in the new site directory and removed obsolete generated parser copies from the plugin checkout. The plugin audit confirmed every plugin is current for its configured branch or release constraint; nvim-surround remains on the latest release rather than its newer unreleased `main` commit. -- 2026-10-28: Fixed stale deleted files persisting across session recreation. Deleting `Session.vim` did not clear the in-memory argument list or listed buffers, so `:mksession` serialized the removed diagnostics fixture again. Session load and exit-time save now discard unmodified nonexistent local-file buffers and missing argument-list entries before restoring or writing the session; real files, URI buffers, unnamed buffers, and modified buffers remain protected. -- 2026-10-28: Re-enabled highlighted netrw file previews after migrating to the Neovim 0.12-compatible nvim-treesitter `main` branch. Preview buffers retain native Tree-sitter or Vim syntax highlighting, while diagnostics and indent guides remain suppressed. The existing loaded-but-unlisted buffer lifecycle protection remains in place so the original unload behavior is not restored. An automated 80-transition Markdown/Lua/JSON/CSS/HTML stress test and subsequent normal use passed without `TSNode:range()` errors, so the trial was adopted as the permanent behavior. - -## Project-Local Configuration - -The final implementation uses Neovim's native `exrc` support with `secure` enabled. A project's trusted `.nvim.lua` returns an `lsp` table keyed by server name. An `LspAttach` callback securely reads settings from the client's actual root directory and sends them with `workspace/didChangeConfiguration`, so settings do not depend on Neovim's current working directory. - -Example `.nvim.lua`: - -```lua -return { - lsp = { - intelephense = { - settings = { - intelephense = { - environment = { - includePaths = { - "wp-content/themes/my-theme", - "wp-content/plugins/custom-plugin", - }, - }, - }, - }, - }, - }, -} -``` - -Neoconf and the earlier layered JSON proposal were rejected. They remain in the chronological decision entries above only as superseded history. - -## LSP Scope (initial) - -- Core servers: `lua_ls`, `tsserver`, `html`, `cssls`, `jsonls`, `bashls` -- PHP: `intelephense` (decision) -- Markdown: `marksman` (decision) -- Keep configuration minimal; defer language-specific tuning. - -## Text & Editing Settings - -- `spelllang = en_gb` -- `listchars` and `showbreak` will reuse legacy values. -- `autocomplete` with `completeopt = menu,menuone,noselect,popup,fuzzy` for Neovim 0.12 native completion. - -## Maintenance Reminders - -- Follow `AGENTS.md` for current maintenance rules. -- Update `README.md` when user-facing behavior changes. -- Record significant architectural decisions in this log. -- Keep changes focused and verify affected workflows. diff --git a/README.md b/README.md deleted file mode 100644 index fedb439..0000000 --- a/README.md +++ /dev/null @@ -1,552 +0,0 @@ -# Neovim Config Reference - -Living reference for session management, keymaps, commands, and plugin-specific features in this config. - -The active runtime is Neovim 0.12.6 through `~/.local/bin/nvim`. Neovim 0.11.5 remains available at `/opt/neovim/nvim-linux-x86_64/bin/nvim` for emergency rollback; the config starts there with 0.12-only native completion and Undotree disabled. - -Persistent undo files are stored outside this repository in -`stdpath('state')/undo` (normally `~/.local/state/nvim/undo`). - -## Session Management - -Session support is automatic but user-controlled: - -**Manual session creation** (one-time): -```vim -:mksession # Creates Session.vim in current directory -``` - -**Auto-load/save** (via `lua/autocmds.lua`): -- On startup: auto-loads `Session.vim` if it exists (unless files specified on command line) -- On exit: auto-saves to `Session.vim` if it already exists -- Netrw and its preview windows are omitted from the saved layout; generated `NetrwTreeListing` buffers are not restorable -- Missing files are removed from restored buffers and argument lists, so deleted files cannot become persistent empty session buffers -- Sessions are per-directory and opt-in (just create one to start using) - -**Stop using a session**: -```bash -rm Session.vim # Won't auto-create a new one -``` - -## Keymaps - -### `:KeymapsGuide` (`lua/keymaps_reference.lua`) - -| Command | Description | -| --- | --- | -| `:KeymapsGuide` | Open a floating window with a dynamically generated list of all user-defined keymaps | - -### `lua/keymaps.lua` - -Core keymaps available globally (not plugin-specific). These provide fallbacks for LSP features and diagnostic navigation. - -| Mode | Key | Description | Notes | -| --- | --- | --- | --- | -| n | `gd` | Vim goto-definition fallback | Executes `normal! gd` for tags/include jumps when no LSP | -| n | `gD` | Vim goto-declaration fallback | Executes `normal! gD` | -| n | `gr` | LSP references placeholder | `` so LSP buffers can override cleanly | -| n | `gI` | LSP implementation placeholder | `` so LSP buffers can override cleanly | -| n | `K` | Keyword help fallback | Uses `keywordprg` (e.g., `man`) when LSP hover is unavailable | -| n | `co` | Quickfix: Open | Opens quickfix window | -| n | `cc` | Quickfix: Close | Closes quickfix window | -| n | `lo` | Location list: Open | Opens location list window | -| n | `lc` | Location list: Close | Closes location list window | -| n | `xx` | Diagnostics → location list | Populates current buffer diagnostics | -| n | `xX` | Diagnostics → quickfix | Populates project-wide diagnostics | -| n | `xe` | Diagnostics → buffer errors | Location list filtered to errors | -| n | `xE` | Diagnostics → all errors | Quickfix filtered to errors | -| n | `[d` | Diagnostics: previous item | Uses `vim.diagnostic.jump` with a negative count | -| n | `]d` | Diagnostics: next item | Uses `vim.diagnostic.jump` with a positive count | -| n | `xd` | Diagnostic float | Opens hover window for cursor diagnostic | -| n | `xt` | Toggle diagnostics | Flips `vim.diagnostic.enable()` | -| n | `gg` | Git: Changed files → quickfix | Lists all modified/deleted/untracked files with status | -| n | `hi` | Highlight inspector | Shows highlight/capture stack under cursor | -| n | `bg` | Toggle background (light/dark) | Switches between light and dark colorscheme modes | - -### `lua/netrw-config.lua` - -#### `:Ex` Command Variants - -| Command | Opens netrw at | -| --- | --- | -| `:Ex` | Current working directory (`:pwd`) | -| `:Ex .` | Current file's directory | -| `:Ex %:h` | Current file's directory (explicit) | -| `:Ex /path/to/dir` | Specific path | - -#### Custom Keymaps - -| Mode | Key | Description | -| --- | --- | --- | -| n | `nt` | Open netrw in new tab at current file's directory | -| n | `nT` | Open netrw in new tab at project root | -| n | `nr` | Open netrw in current window at project root | -| n | `` / `` | Jump to alternate file, skipping netrw explorer buffers | - -**Note:** Project root is stored as the initial working directory when Neovim starts. This allows navigation back to the project root even after following symlinks to external directories. - -#### Default Netrw Keymaps - -##### Navigation & View - -| Key | Description | -| --- | --- | -| `` | Open file/directory under cursor | -| `-` | Go up to parent directory | -| `gh` | Toggle hidden files visibility (dotfiles) | -| `i` | Cycle through view types (thin/long/wide/tree) | -| `s` | Cycle sort order (name/time/size/extension) | -| `r` | Reverse current sort order | -| `I` | Toggle netrw banner (help text) | - -##### Preview & Splits - -| Key | Description | -| --- | --- | -| `p` | Toggle the selected file/directory preview and live cursor updates | -| `j` / `k` | Update an existing preview to the newly selected entry | -| `` / `` | Scroll the preview down/up without leaving netrw; accepts a count | -| `:pclose` / `z` | Close the preview and stop live updates | -| `P` | Open file in previous window | -| `o` | Open file in horizontal split below | -| `v` | Open file in vertical split | -| `t` | Open file in a new tab | - -Regular files use netrw's native preview. Directories show a read-only summary of -their immediate children, including type, file size, modification time, and a -total for immediate files. Directories appear first, output is capped at 200 -entries, and symbolic links are displayed without following them recursively. -File previews retain Tree-sitter or Vim syntax highlighting while suppressing -diagnostics and indent guides. The buffer's prior diagnostic and indent-guide -state returns automatically when a previewed file is opened for editing. -Preview-only file buffers remain loaded but unlisted until Neovim exits, retaining -the lifecycle protection added for rapid preview replacement. - -Opening a file with ``, `o`, `v`, or `t`, or otherwise leaving netrw, closes -the preview. Closing it manually or pressing `p` again disables live updates -until `p` is pressed again. Enhanced directory summaries apply to local paths -(including local paths when Neovim runs over SSH); netrw URI browsing retains -its native preview behavior. - -##### File Operations - -| Key | Description | -| --- | --- | -| `%` | Create new file (prompts for name) | -| `d` | Create new directory (prompts for name) | -| `D` | Delete file/directory under cursor | -| `R` | Rename/move file under cursor | - -##### Marking & Batch Operations - -| Key | Description | -| --- | --- | -| `mf` | Mark file (for batch operations) | -| `mr` | Mark files using regex pattern | -| `mu` | Unmark all marked files | -| `mt` | Set mark target directory (for move/copy destination) | -| `mc` | Copy marked files to target directory | -| `mm` | Move marked files to target directory | -| `qf` | Display file info | - -## Plugin Reference - -### LSP `lua/plugins/lsp.lua` - -#### Keymaps - -Buffer-local keymaps available when an LSP client attaches: - -| Mode | Key | Description | -| --- | --- | --- | -| n | `gd` | LSP: go to definition | -| n | `gr` | LSP: references | -| n | `gD` | LSP: declaration | -| n | `gI` | LSP: implementation | -| n | `K` | LSP hover | - -### Conform (Formatting) `lua/plugins/conform.lua` - -#### Keymaps - -| Mode | Key | Description | -| --- | --- | --- | -| n | `lt` | Toggle format-on-save flag | -| n | `lf` | Format current buffer (synchronous) | -| v | `lf` | Format visual selection | - -### Nvim-lint `lua/plugins/nvim-lint.lua` - -#### Commands - -| Command | Description | -| --- | --- | -| `:MarkdownLintEnable` | Enable automatic markdown linting (runs on BufEnter, BufWritePost, InsertLeave) | -| `:MarkdownLintDisable` | Disable automatic markdown linting and clear diagnostics | - -**Note:** Markdown linting is disabled by default. Spellcheck is always enabled for markdown files. - -### Gitsigns `lua/plugins/gitsigns.lua` - -#### Keymaps - -Buffer-local keymaps available when inside a git repository: - -| Mode | Key | Description | -| --- | --- | --- | -| n | `]h` | Next hunk (`expr` mapping that respects `diff` windows) | -| n | `[h` | Previous hunk | -| n | `hs` | Stage current hunk | -| n | `hr` | Reset current hunk | -| v | `hs` | Stage visually selected range as hunk | -| v | `hr` | Reset visually selected range | -| n | `hS` | Stage entire buffer | -| n | `hu` | Undo last staged hunk | -| n | `hR` | Reset entire buffer | -| n | `hp` | Preview hunk | -| n | `hd` | Diff against index | -| n | `hD` | Diff against previous commit (`~`) | -| n | `hq` | Send all hunks to quickfix list | -| o/x | `ih` | Text object: select git hunk | - -### Telescope `lua/plugins/telescope.lua` - -#### Keymaps - -##### Launcher mappings (normal mode) - -| Key | Description | -| --- | --- | -| `ff` | Find files | -| `fg` | Live grep | -| `fb` | Open buffers picker (`` deletes buffers in picker) | -| `fh` | Help tags | -| `fr` | Recent files (oldfiles) | -| `/` | Fuzzy search current buffer | -| `fk` / `?` | Telescope keymaps picker | -| `fc` | Commands picker | -| `fs` | LSP document symbols | -| `fS` | LSP workspace symbols | - -##### Telescope prompt mappings (`defaults.mappings`) - -| Mode | Key | Description | -| --- | --- | --- | -| i | `` / `` | Move selection down | -| i | `` / `` | Move selection up | -| i | `` | Close picker | -| i | `` | Accept selection | -| i | `` | Open selection in horizontal split | -| i | `` | Open selection in vertical split | -| i | `` | Open selection in tab | -| n | `` | Close picker | -| n | `` | Accept selection | -| n | `` | Horizontal split | -| n | `` | Vertical split | -| n | `` | New tab | -| n | `j` | Move selection down | -| n | `k` | Move selection up | - -##### Picker-specific overrides - -| Context | Mode | Key | Description | -| --- | --- | --- | --- | -| `buffers` picker | i | `` | Delete highlighted buffer | - -### UFO (Folding) `lua/plugins/ufo.lua` - -#### Keymaps - -| Mode | Key | Description | -| --- | --- | --- | -| n | `zR` | Open all folds | -| n | `zM` | Close all folds | -| n | `zr` | Open folds except configured kinds | -| n | `zm` | Close folds with configured kinds | -| n | `K` | Peek fold under cursor; falls back to LSP hover | -| preview window | `` / `` | Scroll within UFO preview | -| preview window | `[` / `]` | Jump to top/bottom of preview | - -### Native Undotree `lua/keymaps.lua` - -#### Keymaps - -| Mode | Key | Description | -| --- | --- | --- | -| n | `u` | Toggle Neovim's native Undotree panel (`:Undotree`) | - -### Treesitter `lua/plugins/treesitter.lua` - -The Neovim 0.12-compatible `main` branches are used for both nvim-treesitter -and nvim-treesitter-textobjects. Highlighting and incremental selection use -Neovim's native APIs; textobjects use explicit plugin mappings. Parser builds -require `tree-sitter-cli` 0.26.1 or newer (`tree-sitter --version`). - -#### Keymaps - -##### Incremental selection - -| Key | Description | -| --- | --- | -| `+` | Initialize/expand selection to the parent node | -| `g+` | Expand to scope | -| `-` | Shrink selection to the child node | - -##### Textobject selection - -| Key | Target | -| --- | --- | -| `af` / `if` | Function outer / inner | -| `ac` / `ic` | Class outer / inner | -| `aa` / `ia` | Parameter outer / inner | -| `ai` / `ii` | Conditional outer / inner | -| `al` / `il` | Loop outer / inner | -| `a/` | Comment outer | - -##### Textobject movement - -| Key | Action | -| --- | --- | -| `]f` / `]F` | Next function start / end | -| `[f` / `[F` | Previous function start / end | -| `]c` / `]C` | Next class start / end | -| `[c` / `[C` | Previous class start / end | -| `]a` / `]A` | Next parameter start / end | -| `[a` / `[A` | Previous parameter start / end | - -##### Parameter swapping - -| Key | Description | -| --- | --- | -| `a` | Swap parameter with next | -| `A` | Swap parameter with previous | - -### Comment.nvim `lua/plugins/comment.lua` - -#### Keymaps - -| Mapping | Description | -| --- | --- | -| `gcc` | Toggle line comment | -| `gbc` | Toggle block comment | -| `gc` | Operator-pending line comment | -| `gb` | Operator-pending block comment | -| `gcO` / `gco` / `gcA` | Insert comment above / below / end-of-line | - -### Nvim-surround `lua/plugins/surround.lua` - -The configuration uses nvim-surround v4's default mappings. - -#### Keymaps - -| Mode | Mapping | Description | -| --- | --- | --- | -| normal | `ys{motion}{char}` | Add surround to motion | -| normal | `yss` | Surround current line | -| normal | `yS` | Surround motion with linewise behavior | -| normal | `ySS` | Surround current line linewise | -| insert | `s` | Surround following text object | -| insert | `S` | Surround current line | -| visual | `S` | Surround selection | -| visual line | `gS` | Surround visual-line selection | -| normal | `ds{char}` | Delete surround | -| normal | `cs{old}{new}` | Change surround | -| normal | `cS{old}{new}` | Change surround (linewise) | - -### Native Completion `lua/completion.lua` - -#### Keymaps - -| Mode | Key | Description | -| --- | --- | --- | -| insert | `` | Manually trigger LSP completion | -| insert | `` | Next completion item | -| insert | `` | Previous completion item | -| insert | `` | Accept the explicitly selected completion item | -| insert | `` | Dismiss the completion menu | -| insert | `` | Complete words from the current buffer | -| insert | `` | Complete a filesystem path | -| insert/select | `` / `` | Jump forward/backward through native snippet tabstops | - -Completion opens automatically after a 150 ms delay, uses fuzzy matching, and does not preselect an item. LSP buffers prioritize language-aware results exclusively; buffer words remain available explicitly with ``. Buffers without an LSP autocomplete from a bounded set of nearby words. Native completion is disabled in Telescope prompts so it does not obscure picker results. - -### Copilot Inline Suggestions `lua/plugins/copilot.lua` - -Copilot appears as ghost text rather than as an item in the native completion menu. Suggestions are hidden while that menu is visible. - -| Mode | Key | Description | -| --- | --- | --- | -| insert | `` | Accept the visible Copilot suggestion | -| insert | `` | Show the next Copilot suggestion | -| insert | `` | Show the previous Copilot suggestion | -| insert | `` | Dismiss the Copilot suggestion | - -### Nvim-autopairs `lua/plugins/autopairs.lua` - -#### Keymaps - -| Mode | Key | Description | -| --- | --- | --- | -| insert | `` | Fast wrap the previous text with a pair | - -## Configuration - -### Colorscheme - -`paper-tonic-modern` is built into this repository and loaded from `colors/paper-tonic-modern.lua`. Its modular highlight definitions live under `lua/paper-tonic-modern/` and cover the editor UI, traditional syntax, Tree-sitter captures, LSP diagnostics, and the configured plugins. - -The theme follows the system light/dark preference at startup. Use `bg` to toggle the background manually. Custom HTML and CSS Tree-sitter queries keep matching classes and IDs visually consistent across both languages. - -### Project-Local LSP Settings - -Native `exrc` and `secure` support are enabled. A trusted `.nvim.lua` can return an `lsp` table keyed by server name; settings are securely read from the attached LSP client's root and sent through `workspace/didChangeConfiguration`. - -```lua -return { - lsp = { - intelephense = { - settings = { - intelephense = { - environment = { - includePaths = { "vendor/package/src" }, - }, - }, - }, - }, - }, -} -``` - -### Formatting & Linting - -This config uses **conform.nvim** for formatting and **nvim-lint** for diagnostics. Both prefer project-local tools over global installations. - -#### Executable Resolution Order - -When looking for formatters/linters, the config searches in this priority: - -1. **Project-local** (e.g., `node_modules/.bin/`, `vendor/bin/`) -2. **Mason-managed** (`~/.local/share/nvim/mason/bin/`) -3. **System PATH** (globally installed tools) - -Conform.nvim handles this resolution automatically via its built-in `util.find_executable()`. nvim-lint uses a custom `find_executable()` helper in `lua/plugins/nvim-lint.lua`. - -#### Configured Tools - -**Formatters** (`lua/plugins/conform.lua`): -- **JavaScript/TypeScript/CSS/JSON/HTML/Markdown**: `prettier` -- **PHP**: `phpcbf` (WordPress standard by default) -- **Lua**: `stylua` -- **Python**: `ruff_format` - -**Linters** (`lua/plugins/nvim-lint.lua`): -- **JavaScript/TypeScript**: `eslint_d` -- **PHP**: `phpcs` (WordPress standard by default) -- **Markdown**: `markdownlint` (disabled by default; use `:MarkdownLintEnable`) -- **Python**: handled by `ruff` LSP (not nvim-lint) - -#### Project-Specific Overrides - -Both formatters and linters respect project-level configuration files: - -**PHP** (phpcbf + phpcs): -- Create `phpcs.xml` or `phpcs.xml.dist` in your project root -- When present, this file controls the coding standard (e.g., PSR-12, WordPress, custom) -- When absent, defaults to `--standard=WordPress` - -Example `phpcs.xml`: -```xml - - - Project-specific PHP rules - - - - - - - - - - -``` - -**JavaScript/TypeScript** (prettier + eslint): -- Project config files: `.prettierrc`, `.eslintrc.json`, `eslint.config.js`, etc. -- Global fallback: `~/.eslintrc.json` (when no project config exists) - -**Lua** (stylua): -- Project config: `stylua.toml` or `.stylua.toml` -- Falls back to stylua defaults if not present - -**Markdown** (markdownlint): -- Project config: `.markdownlint.json`, `.markdownlintrc` - -#### Changing Standards Per-Project - -To switch a PHP project from WordPress to PSR-12: - -1. Create `phpcs.xml` in project root: - ```xml - - - - - ``` - -2. Restart Neovim (or reload config: `:source $MYVIMRC`) - -Both `phpcs` and `phpcbf` will now use PSR-12 rules in that project. - -#### Format-on-Save - -- **Enabled by default** for all supported filetypes -- **Toggle**: `lt` (see keymaps below) -- **Manual format**: `lf` (buffer or visual selection) - -#### Linting Behavior - -- **Automatic**: Runs on `BufEnter`, `BufWritePost`, `InsertLeave` -- **Per-filetype**: Configured in `lint.linters_by_ft` table -- **Markdown**: Opt-in only (`:MarkdownLintEnable` / `:MarkdownLintDisable`) - -## Configuration Options - -### Tabline Display - -Custom tabline shows intelligent path shortening with two configurable options. - -**Location:** `lua/settings.lua` (configured via `utils.tabline_full_parents` and `utils.tabline_shorten_length`) - -**Configuration Options:** - -1. **`utils.tabline_full_parents`** (default: `1`) - Number of parent directories to show in full -2. **`utils.tabline_shorten_length`** (default: `3`) - Number of characters to show for shortened directories - -**Examples:** - -With `full_parents = 1, shorten_length = 3`: -- `/path/to/my/project/src/file.txt` → `pat/to/my/project/src/file.txt` - -With `full_parents = 2, shorten_length = 3`: -- `/path/to/my/project/src/file.txt` → `pat/to/my/project/src/file.txt` - -With `full_parents = 1, shorten_length = 1`: -- `/path/to/my/project/src/file.txt` → `p/t/m/project/src/file.txt` - -With `full_parents = 0, shorten_length = 3`: -- `/path/to/my/project/src/file.txt` → `pat/to/my/pro/src/file.txt` - -The last N parent directories are shown in full, earlier directories are shortened to the specified number of characters. The filename itself is always shown in full. - -**To customize:** Edit `utils.tabline_full_parents` and `utils.tabline_shorten_length` values in `lua/settings.lua` - -## Working Directory Behavior - -The working directory (`:pwd`) is locked to the directory where you opened Neovim and does NOT change when switching files: - -- `autochdir` is disabled (working directory stays fixed at project root) -- `netrw_keepdir = 1` prevents netrw from changing directory when browsing -- Project root is captured at startup in `vim.g.project_root` (used by Telescope and netrw) -- Telescope searches from the initial project root regardless of current buffer -- Use `:cd ` to manually change directory if needed (affects Telescope search scope) diff --git a/Session.ts.vim b/Session.ts.vim new file mode 100644 index 0000000..c66c0f5 --- /dev/null +++ b/Session.ts.vim @@ -0,0 +1,149 @@ +let SessionLoad = 1 +let s:so_save = &g:so | let s:siso_save = &g:siso | setg so=0 siso=0 | setl so=-1 siso=-1 +let v:this_session=expand(":p") +silent only +silent tabonly +cd ~/.config/nvim +if expand('%') == '' && !&modified && line('$') <= 1 && getline(1) == '' + let s:wipebuf = bufnr('%') +endif +set shortmess=aoO +badd +36 init.tabline.vim +badd +22 init.auto-window.vim +badd +1 coc-settings.json +badd +184 init.vim +badd +1 ftplugin/php.vim +badd +2 after/ftplugin/php.vim +badd +1 after/ftplugin/html.vim +badd +1 after/ftplugin/javascript.vim +badd +8 after/ftplugin/python.vim +badd +1 after/ftplugin/sass.vim +badd +1 after/ftplugin/vim.vim +badd +1 ftplugin/vue.vim +badd +1 ftplugin/sass.vim +badd +1 ftplugin/javascript.vim +badd +1 ftplugin/css.vim +badd +50 init.plugins.vim +badd +1 after/indent/php.vim +badd +10 init.commands.vim +badd +7 lua/init-plugins.lua +badd +1 after/queries/ecma/highlights.scm +badd +16 after/queries/html/highlights.scm +badd +2 after/queries/css/highlights.scm +argglobal +%argdel +$argadd init.tabline.vim +edit after/queries/css/highlights.scm +let s:save_splitbelow = &splitbelow +let s:save_splitright = &splitright +set splitbelow splitright +wincmd _ | wincmd | +vsplit +1wincmd h +wincmd _ | wincmd | +split +1wincmd k +wincmd w +wincmd w +let &splitbelow = s:save_splitbelow +let &splitright = s:save_splitright +wincmd t +let s:save_winminheight = &winminheight +let s:save_winminwidth = &winminwidth +set winminheight=0 +set winheight=1 +set winminwidth=0 +set winwidth=1 +exe '1resize ' . ((&lines * 22 + 25) / 50) +exe 'vert 1resize ' . ((&columns * 103 + 105) / 211) +exe '2resize ' . ((&lines * 22 + 25) / 50) +exe 'vert 2resize ' . ((&columns * 103 + 105) / 211) +exe 'vert 3resize ' . ((&columns * 107 + 105) / 211) +argglobal +balt after/queries/html/highlights.scm +setlocal fdm=indent +setlocal fde=0 +setlocal fmr={{{,}}} +setlocal fdi=# +setlocal fdl=99 +setlocal fml=1 +setlocal fdn=9 +setlocal fen +let s:l = 3 - ((2 * winheight(0) + 11) / 22) +if s:l < 1 | let s:l = 1 | endif +keepjumps exe s:l +normal! zt +keepjumps 3 +normal! 023| +lcd ~/.config/nvim +wincmd w +argglobal +if bufexists("/usr/share/nvim/runtime/doc/treesitter.txt") | buffer /usr/share/nvim/runtime/doc/treesitter.txt | else | edit /usr/share/nvim/runtime/doc/treesitter.txt | endif +if &buftype ==# 'terminal' + silent file /usr/share/nvim/runtime/doc/treesitter.txt +endif +setlocal fdm=manual +setlocal fde=0 +setlocal fmr={{{,}}} +setlocal fdi=# +setlocal fdl=99 +setlocal fml=1 +setlocal fdn=9 +setlocal nofen +silent! normal! zE +let &fdl = &fdl +let s:l = 196 - ((5 * winheight(0) + 11) / 22) +if s:l < 1 | let s:l = 1 | endif +keepjumps exe s:l +normal! zt +keepjumps 196 +normal! 050| +lcd ~/.config/nvim +wincmd w +argglobal +if bufexists("~/.config/nvim/after/indent/php.vim") | buffer ~/.config/nvim/after/indent/php.vim | else | edit ~/.config/nvim/after/indent/php.vim | endif +if &buftype ==# 'terminal' + silent file ~/.config/nvim/after/indent/php.vim +endif +setlocal fdm=marker +setlocal fde=0 +setlocal fmr={{{,}}} +setlocal fdi=# +setlocal fdl=99 +setlocal fml=1 +setlocal fdn=9 +setlocal fen +let s:l = 4 - ((3 * winheight(0) + 22) / 45) +if s:l < 1 | let s:l = 1 | endif +keepjumps exe s:l +normal! zt +keepjumps 4 +normal! 03| +lcd ~/.config/nvim +wincmd w +exe '1resize ' . ((&lines * 22 + 25) / 50) +exe 'vert 1resize ' . ((&columns * 103 + 105) / 211) +exe '2resize ' . ((&lines * 22 + 25) / 50) +exe 'vert 2resize ' . ((&columns * 103 + 105) / 211) +exe 'vert 3resize ' . ((&columns * 107 + 105) / 211) +if exists(':tcd') == 2 | tcd ~/.config/nvim | endif +tabnext 1 +if exists('s:wipebuf') && len(win_findbuf(s:wipebuf)) == 0&& getbufvar(s:wipebuf, '&buftype') isnot# 'terminal' + silent exe 'bwipe ' . s:wipebuf +endif +unlet! s:wipebuf +set winheight=1 winwidth=20 shortmess=aoOT +let &winminheight = s:save_winminheight +let &winminwidth = s:save_winminwidth +let s:sx = expand(":p:r")."x.vim" +if filereadable(s:sx) + exe "source " . fnameescape(s:sx) +endif +let &g:so = s:so_save | let &g:siso = s:siso_save +set hlsearch +let g:this_session = v:this_session +let g:this_obsession = v:this_session +let g:this_obsession_status = 2 +doautoall SessionLoadPost +unlet SessionLoad +" vim: set ft=vim : diff --git a/UltiSnips/all.snippets b/UltiSnips/all.snippets new file mode 100644 index 0000000..59f054e --- /dev/null +++ b/UltiSnips/all.snippets @@ -0,0 +1,3 @@ +snippet tp "{% partial ... " i +{% partial '$1'$0 %} +endsnippet diff --git a/UltiSnips/css.snippets b/UltiSnips/css.snippets new file mode 100644 index 0000000..f0595d6 --- /dev/null +++ b/UltiSnips/css.snippets @@ -0,0 +1,265 @@ +snippet abs "pabs position: absolute;" +position: absolute; +endsnippet +snippet fix "position: fixed;" +position: fixed; +endsnippet +snippet rel "position: relative;" +position: relative; +endsnippet +snippet row "flex-direction: row;" +flex-direction: row; +endsnippet +snippet col "flex-direction: column;" +flex-direction: column; +endsnippet +snippet over "overflow: hidden;" +overflow: $0; +endsnippet + +snippet style "/* stylelint-disable-next-line ... */" +/* stylelint-disable-next-line ${1:declaration-block-no-shorthand-property-overrides} */ +endsnippet + +snippet @m "@media ( ..." +@media (${1:min-width}: ${2:$bp-${3:s}-min}) { + $0 +} +endsnippet + +snippet @max "@media (max-width: ..." +@media (max-width: ${2:$bp-${3:s}-max}) { + $0 +} +endsnippet + +snippet @min "@media (min-width: ..." +@media (min-width: ${2:$bp-${3:s}-min}) { + $0 +} +endsnippet + +snippet lg "linear-gradient( ... )" +linear-gradient( + ${1:to bottom}, + ${2:transparent}, + ${3:transparent} +)$0 +endsnippet + +snippet bglg "background: linear-gradient ..." +background-image: linear-gradient( + ${2:to bottom}, + ${3:transparent}, + ${4:transparent} + ); +endsnippet + +snippet flex "display: flex ..." +display: flex;${1: +flex-direction: ${2:column};} +justify-content: ${3:center}; +align-items: ${4:center}; +endsnippet + +snippet w "width: ;" +width: ${1:100%}; +endsnippet + +snippet h "height: ;" +height: ${1:100%}; +endsnippet + +snippet wh "width: ; height: ;" +width: ${1:100%}; +height: $1; +endsnippet + +snippet mxw "max-width: ;" +max-width: ${1:100%}; +endsnippet + +snippet mxh "max-height: ;" +max-height: ${1:100%}; +endsnippet + +snippet mnw "min-width: ;" +min-width: ${1:100%}; +endsnippet + +snippet mnh "min-height: ;" +min-height: ${1:100%}; +endsnippet + +snippet bgc "background-color: ;" +background-color: ${1:transparent}; +endsnippet + +snippet t "top: ... ;" +top: ${1:0}; +endsnippet + +snippet b "bottom: ... ;" +bottom: ${1:0}; +endsnippet + +snippet l "left: ... ;" +left: ${1:0}; +endsnippet + +snippet r "right: ... ;" +right: ${1:0}; +endsnippet + +snippet bd "border: ... ;" +border: ${1:1px} ${2:solid} ${3:currentColor}; +endsnippet + +snippet bdt "border-top: ... ;" +border-top: ${1:1px} ${2:solid} ${3:currentColor}; +endsnippet + +snippet bdb "border-bottom: ... ;" +border-bottom: ${1:1px} ${2:solid} ${3:currentColor}; +endsnippet + +snippet bdl "border-left: ... ;" +border-left: ${1:1px} ${2:solid} ${3:currentColor}; +endsnippet + +snippet bdr "border-right: ... ;" +border-right: ${1:1px} ${2:solid} ${3:currentColor}; +endsnippet + +snippet br "border-radius: ... ;" +border-radius: ${1:50%}; +endsnippet + +snippet m "margin: ... ;" +margin: ${1:0}; +endsnippet + +snippet mt "margin-top: ... ;" +margin-top: ${1:0}; +endsnippet + +snippet mb "margin-bottom: ... ;" +margin-bottom: ${1:0}; +endsnippet + +snippet ml "margin-left: ... ;" +margin-left: ${1:0}; +endsnippet + +snippet mr "margin-right: ... ;" +margin-right: ${1:0}; +endsnippet + +snippet p "padding: ... ;" +padding: ${1:0}; +endsnippet + +snippet pt "padding-top: ... ;" +padding-top: ${1:0}; +endsnippet + +snippet pb "padding-bottom: ... ;" +padding-bottom: ${1:0}; +endsnippet + +snippet pl "padding-left: ... ;" +padding-left: ${1:0}; +endsnippet + +snippet pr "padding-right: ... ;" +padding-right: ${1:0}; +endsnippet + +snippet fs "font-size: ... ;" +font-size: ${1:1}${2:rem}; +endsnippet + +snippet fw "font-weight: ... ;" +font-weight: ${1:bold}; +endsnippet + +snippet o "opacity: ... ;" +opacity: ${1:0}; +endsnippet + +snippet grid "display: grid ..." +display: grid; +grid-template-columns: $1; +grid-template-rows: $0; +endsnippet + +snippet gr "grid-row: ... ;" +grid-row: $0; +endsnippet + +snippet gc "grid-column: ... ;" +grid-column: $0; +endsnippet + +snippet rgbw "rgba( ... )" +rgba(${1:#fff}, ${2:0.5}) +endsnippet + +snippet rgbb "rgba( ... )" +rgba(${1:#000}, ${2:0.5}) +endsnippet + +snippet before "::before { ... }" +${1:&}::before { + content: '$2'; + display: ${3:block}; + position: ${4:absolute}; + width: ${5:100%}; + height: ${6:100%}; + ${7:top}: ${8:0}; + ${9:left}: ${10:0}; +} +endsnippet + +snippet after "::after { ... }" +${1:&}::after { + content: '$2'; + display: ${3:block}; + position: ${4:absolute}; + width: ${5:100%}; + height: ${6:100%}; + ${7:top}: ${8:0}; + ${9:left}: ${10:0}; +} +endsnippet + +snippet befaft "::before, ::after { ... }" +${1:&}::before { +$1::after { + content: '$2'; + display: ${3:block}; + position: ${4:absolute}; + width: ${5:100%}; + height: ${6:100%}; + ${7:top}: ${8:0}; + ${9:left}: ${10:0}; + $0 +} +endsnippet + +snippet bs "box-shadow ...;" +box-shadow: ${1:0} ${2:0} $3px $4px ${5:#000} ${6:inset}; +endsnippet + +snippet pabs "Position: absolute ..." +position: absolute; +inset: 0; +endsnippet + +snippet v "var(--...)" +var(--$0) +endsnippet + +snippet ftscss "/* vim: set filetype=scss: */" +/* vim: set filetype=scss: */ +endsnippet diff --git a/UltiSnips/dosini.snippets b/UltiSnips/dosini.snippets new file mode 100644 index 0000000..5283cc8 --- /dev/null +++ b/UltiSnips/dosini.snippets @@ -0,0 +1,3 @@ +snippet polycolor "${colors.color}" +\$\{colors.${1:foreground}}$0 +endsnippet diff --git a/UltiSnips/eruby.snippets b/UltiSnips/eruby.snippets new file mode 100644 index 0000000..fb247de --- /dev/null +++ b/UltiSnips/eruby.snippets @@ -0,0 +1,3 @@ +snippet cldef "Colour definition" +$1 = ["#$2", $3, "$4"] +endsnippet diff --git a/UltiSnips/html.snippets b/UltiSnips/html.snippets new file mode 100644 index 0000000..6f60e5b --- /dev/null +++ b/UltiSnips/html.snippets @@ -0,0 +1,106 @@ +snippet html5 "HTML% boilerplate." + + + + + + ${2: + } + $1 + + $0 ${4: + } + + +endsnippet + +snippet option "$0 +endsnippet + +snippet c "class= ... " +class="$1"$0 +endsnippet + +snippet plc " { + $0 +}); +endsnippet + +snippet .ael "...addEventListener( ... );" i +.addEventListener('$1', ($2) => { + $0 +}); +endsnippet + +snippet st "setTimeout( ... )" +setTimeout(() => {$0 +}, ${1:1000}); +endsnippet + +snippet dq "document.querySelector( ... )" +document.querySelector($0) +endsnippet + +snippet dqa "document.querySelectorAll( ... )" +document.querySelectorAll($0) +endsnippet + +snippet cdq "const ... = document.querySelector( ... )" +const $1 = document.querySelector($0); +endsnippet + +snippet cdqa "const ... = document.querySelectorAll( ... )" +const $1 = document.querySelectorAll($0); +endsnippet + +snippet jsx "import React ..." +import * as React from "react";${1: +import { css } from "@emotion/react";} + +const `!p snip.rv = snip.basename` = ($2) => { + return ( +
$0 +
+ ); +}; + +export default `!p snip.rv = snip.basename`; +endsnippet + + +snippet isi "import { StaticImage } ..." +import { StaticImage } from "gatsby-plugin-image"; +endsnippet + +snippet simg "" +$0 +endsnippet + +snippet st. "styled." +const $1 = styled.${2:div}\` + $0 +\`; +endsnippet + +snippet icss "import ... from ..." +import \{ css \} from "@emotion/react"; +endsnippet + +snippet ccs "const ..Css=css``" +const $1Css = css\` + $0 +\`; +endsnippet + +snippet cse "css={css``}" +css={css\`$0\`} +endsnippet + +snippet css "css={..Css}" +css={$0Css} +endsnippet + +snippet th "this.handle..." +this.handle${1:Click} = this.handle$1.bind(this); +endsnippet + +snippet tb "this ... = ... .bind(this);" +this.$1 = this.$1.bind(this); +endsnippet + +snippet wprb +import { registerBlockType } from '@wordpress/blocks'; + +const blockStyle = { + color: red, + backgroundColor: pink, +}; + +registerBlockType( '${1:namespace}/${2:block-name}', { + title: '$3', + icon: '${4:universal-access-alt}', + category: '${5:layout}', + example: {}, + edit( { className } ) { + return
Hello World, step 1 (from the editor).
; + }, + save() { + return
Hello World, step 1 (from the frontend).
; + }, +} ); +endsnippet + +snippet rtw "React + twin.macro" +import * as React from "react" +import 'twin.macro' + +const `!p snip.rv = snip.basename` = ({ children }) => { + return ( + <$1 tw="$0"> + {children} + + ) +} + +export default `!p snip.rv = snip.basename` + +endsnippet + +snippet ue "useEffect(() => {" +useEffect(() => { + $0 +}, ${1:[]}); +endsnippet + +snippet ule "useLayoutEffect(() => {" +useLayoutEffect(() => { + $0 +}, ${1:[]}); +endsnippet + +snippet imp "import ... from ..." +import $1 from "${2:.}/$1"; +endsnippet diff --git a/UltiSnips/javascriptreact.snippets b/UltiSnips/javascriptreact.snippets new file mode 100644 index 0000000..4002f24 --- /dev/null +++ b/UltiSnips/javascriptreact.snippets @@ -0,0 +1 @@ +extends css, javascript diff --git a/UltiSnips/jinja.snippets b/UltiSnips/jinja.snippets new file mode 100644 index 0000000..f1456bf --- /dev/null +++ b/UltiSnips/jinja.snippets @@ -0,0 +1,33 @@ +extends html + +snippet com "{# .. #}" +{# $0 #} +endsnippet + +snippet import "{% import ... %}" +{% import "$1" as $2 %} +endsnippet + +snippet macro "{% macro ...%}" +{% macro $1(${2:$3="$4"}) %} + $0 +{% endmacro %} +endsnippet + +snippet blockin "{% block .. %}" +{% block $1 %}$0{% endblock %} +endsnippet + +snippet block "{% block .. %}" +{% block $1 %} + $0 +{% endblock %} +endsnippet + +snippet include "{% include .. %}" +{% include "$0" %} +endsnippet + +snippet extends "{% extends .. %}" +{% extends "$0" %} +endsnippet diff --git a/UltiSnips/jst.snippets b/UltiSnips/jst.snippets new file mode 100644 index 0000000..1510065 --- /dev/null +++ b/UltiSnips/jst.snippets @@ -0,0 +1,19 @@ +snippet req "<%- require( ..." +<%- require('!!ejs-compiled-loader?{}!./$1.ejs')($0) %> +endsnippet + +snippet % "<% ... %>" +<% $0 %> +endsnippet + +snippet = "<= ... =>" +<%= $0 %> +endsnippet + +snippet - "<- ... ->" +<%- $0 %> +endsnippet + +snippet # "<# ... #>" +<%# $0 %> +endsnippet diff --git a/UltiSnips/markdown.snippets b/UltiSnips/markdown.snippets new file mode 100644 index 0000000..82f3df3 --- /dev/null +++ b/UltiSnips/markdown.snippets @@ -0,0 +1,83 @@ +snippet l "[...](...)" +[${1:title}](${2:url})$0 +endsnippet + +snippet c "``` ..." +\`\`\`$0 +\`\`\` +endsnippet + +# latex +snippet vec "vector 1x2" i +\\begin{bmatrix} $1 \\\\ $2 \\end{bmatrix}$0 +endsnippet + +snippet vec3 "vector 1x3" i +\\begin{bmatrix} $1 \\\\ $2 \\\\ $3 \\end{bmatrix}$0 +endsnippet + +snippet mx "matrix 2x2" i +\\begin{bmatrix} $1 & $2 \\\\ $3 & $4 \\end{bmatrix}$0 +endsnippet + +snippet mx3 "matrix 3x3" i +\\begin{bmatrix} $1 & $2 & $3 \\\\ $4 & $5 & $6 \\\\ $7 & $8 & $9 \\end{bmatrix}$0 +endsnippet + +snippet lim "limit" i +\\lim{$1 \\to $2}$0 +endsnippet + +snippet sum "sum" i +\\sum_{$1}^{$2}$0 +endsnippet + +snippet fr "fraction" i +\\frac{$1}{$2}$0 +endsnippet + +snippet sq "square root" i +\\sqrt{$1}$0 +endsnippet + +snippet rt "root" i +\\sqrt[${1:3}]{${2:x}}$0 +endsnippet + +snippet br "{}" i +\\lbrace $1 \\rbrace$0 +endsnippet + +snippet | "|...|" +\\lvert $1 \\rvert$0 +endsnippet + +snippet || "|...|" +\\lVert $1 \\rVert$0 +endsnippet + +snippet ds "displaystyle" i +\\displaystyle$0 +endsnippet + +snippet lmb "lambda" i +\\lambda$0 +endsnippet + +snippet imp "implies" i +\\Rightarrow +endsnippet + +snippet int "integral" i +\\int_{$1}^{$2} $0 +endsnippet + +snippet web "web snippet" +[$1]($2) + +\`\`\` +$3 +\`\`\` + +---$0 +endsnippet diff --git a/UltiSnips/octobercms.snippets b/UltiSnips/octobercms.snippets new file mode 100644 index 0000000..7734ab5 --- /dev/null +++ b/UltiSnips/octobercms.snippets @@ -0,0 +1,3 @@ +snippet pl "{% partial ... %}" +{% partial "$0" %} +endsnippet diff --git a/UltiSnips/php.snippets b/UltiSnips/php.snippets new file mode 100644 index 0000000..857246f --- /dev/null +++ b/UltiSnips/php.snippets @@ -0,0 +1,95 @@ +extends html + +snippet doc "/**" +/** + * $1 + */$0 +endsnippet + +snippet pre "
print_r()
" +echo "
";
+print_r($0);
+echo "
"; +endsnippet + +snippet if "if () {}" +if ($1) { + $0 +} +endsnippet + +snippet fe "foreach () {}" +foreach (\$${1:array} as \$${2:item}) { + $0 +} +endsnippet + +snippet pp "" + +endsnippet + +snippet pe "" + +endsnippet + +snippet ph "" + +endsnippet + +snippet pf "public function ..." +public function $1($2) { + $0 +} +endsnippet + +snippet pt "protected function ..." +protected function $1($2) { + $0 +} +endsnippet + +snippet pv "private function ..." +private function $1($2) { + $0 +} +endsnippet + +snippet psf "public static function ..." +public static function $1($2) { + $0 +} +endsnippet + +snippet prsf "public static function ..." +private static function $1($2) { + $0 +} +endsnippet + +snippet ''= "'...' => " +'$1' => $0, +endsnippet + +snippet apm "add_post_meta(..." +add_post_meta( ${1:2720}, '__DEBUG__$2', $0); +endsnippet + +snippet upm "update_post_meta(..." +update_post_meta( ${1:2720}, '__DEBUG__$1', $0); +endsnippet + +snippet sw "switch ..." +switch ($1) { + case $2: + $3; + break; + default: + $0 +} +endsnippet + +snippet cs "case ..." +case $1: + $0; + break; +endsnippet diff --git a/UltiSnips/python.snippets b/UltiSnips/python.snippets new file mode 100644 index 0000000..e4071e5 --- /dev/null +++ b/UltiSnips/python.snippets @@ -0,0 +1,19 @@ +snippet qxconfig "qutebrowser xResources config" +c.colors.messages.$1 = xresources['*${2:background}']$0 +endsnippet + +snippet main "if __name__ == .." +def main(): + $0 + +if __name__ == "__main__": + main() +endsnippet + +snippet ld "logger.debug()" +logger.debug("$1".format($2)) +endsnippet + +snippet li "logger.info()" +logger.info("$1".format($2)) +endsnippet diff --git a/UltiSnips/scss.snippets b/UltiSnips/scss.snippets new file mode 100644 index 0000000..7ac57c6 --- /dev/null +++ b/UltiSnips/scss.snippets @@ -0,0 +1,49 @@ +extends css + +snippet @i "@include" +@include $0; +endsnippet + +snippet imt "@include margin-t( );" +@include margin-t(${0:1}); +endsnippet + +snippet imb "@include margin-b( );" +@include margin-b(${0:1}); +endsnippet + +snippet imv "@include margin-v( , );" +@include margin-v($0); +endsnippet + +snippet im "@include margin( , , , );" +@include margin($0); +endsnippet + +snippet ipt "@include pad-t( );" +@include pad-t(${0:1}); +endsnippet + +snippet ipb "@include pad-b( );" +@include pad-b(${0:1}); +endsnippet + +snippet iph "@include pad-v( , );" +@include pad-h($0); +endsnippet + +snippet ipv "@include pad-v( , );" +@include pad-v($0); +endsnippet + +snippet ipl "@include pad-l( );" +@include pad-l(${0:1}); +endsnippet + +snippet ipr "@include pad-r( );" +@include pad-r(${0:1}); +endsnippet + +snippet ip "@include pad( , , , );" +@include pad($0); +endsnippet diff --git a/UltiSnips/sh.snippets b/UltiSnips/sh.snippets new file mode 100644 index 0000000..6162f29 --- /dev/null +++ b/UltiSnips/sh.snippets @@ -0,0 +1,3 @@ +snippet polybashcolor "%{{F{color}}}" i +%\{\{F\{color${1:4}}}} +endsnippet diff --git a/UltiSnips/vim.snippets b/UltiSnips/vim.snippets new file mode 100644 index 0000000..5b33be8 --- /dev/null +++ b/UltiSnips/vim.snippets @@ -0,0 +1,7 @@ +snippet scolor "SetColor('', .." +SetColor('$1', '$2', '$3', '$4', '$5', '$6')$0 +endsnippet + +snippet cscolor "call SetColor('', .." +call SetColor('$1', '$2', '$3', '$4', '$5', '$6')$0 +endsnippet diff --git a/UltiSnips/vue.snippets b/UltiSnips/vue.snippets new file mode 100644 index 0000000..f7d888c --- /dev/null +++ b/UltiSnips/vue.snippets @@ -0,0 +1,154 @@ +extends html, javascript, scss + +snippet vue "Default template" + + + + + +endsnippet + +snippet byinput "Beufy Input Field" +
+ +
+ +
+
$0 +endsnippet + +snippet byselect "Buefy Select Field" +
+ +
+
+ +
+
+
+endsnippet + +snippet nt "this.$nextTick( () => { ... })" +this.$nextTick( () => { + $0 +}) +endsnippet + +snippet props "props: { ... }" +props: { + $1: { + type: ${2:Boolean}, + required: ${3:false}, + default() { + return ${4:false}; + }, + }, +},$0 +endsnippet + +snippet prop "property: { ... }" +$1: { + type: ${2:Boolean}, + required: ${3:false}, + default() { + return ${4:false}; + }, +},$0 +endsnippet + +snippet comps "components { ... }" +components: { + $0, +}, +endsnippet + +snippet data "data() { return { ... } }" +data() { + return { + $1: $2,$0 + }; +}, +endsnippet + +snippet compd "computed: { ... }" +computed: { + $1() { + $0 + }, +}, +endsnippet + +snippet meth "methods: { ... }" +methods: { + $1() { + $0 + }, +}, +endsnippet + +snippet style " +endsnippet + +snippet impc "import ... from '~/components...';" +import $1 from '~/components/$1';$0 +endsnippet + +snippet tran " + ${VISUAL}$0 + +endsnippet + +snippet .tran "vue transition selector" +.$1 { + &-enter-active { + transition: ${2:opacity} ${3:1}s; + } + + &-leave-active { + transition: $2 ${4:1}s; + } + + &-enter, + &-leave-to { + $2: ${5:0}; + } +}$0 +endsnippet + +snippet script "" + +endsnippet + +snippet s ":style='{ ... }" +:style="{ '$1': $2 }"$0 +endsnippet diff --git a/after/ftplugin/help.vim b/after/ftplugin/help.vim new file mode 100644 index 0000000..aa798a4 --- /dev/null +++ b/after/ftplugin/help.vim @@ -0,0 +1 @@ +nmap q :q diff --git a/after/ftplugin/html.vim b/after/ftplugin/html.vim new file mode 100644 index 0000000..a06a63b --- /dev/null +++ b/after/ftplugin/html.vim @@ -0,0 +1 @@ +setlocal foldnestmax=5 diff --git a/after/ftplugin/javascript.vim b/after/ftplugin/javascript.vim new file mode 100644 index 0000000..101be7c --- /dev/null +++ b/after/ftplugin/javascript.vim @@ -0,0 +1,107 @@ +" https://gist.github.com/romainl/1f50c55b0ee92e5420de51e6c4b38491 + +nnoremap cF :call CocAction('runCommand', 'eslint.executeAutofix') + +setlocal includeexpr=RESOLVE(v:fname) + +function! RESOLVE(module) abort + let built_ins = [ + \ "assert", + \ "async_hooks", + \ "child_process", + \ "cluster", + \ "crypto", + \ "dns", + \ "domain", + \ "events", + \ "fs", + \ "http", + \ "http2", + \ "https", + \ "inspector", + \ "net", + \ "os", + \ "path", + \ "perf_hooks", + \ "punycode", + \ "querystring", + \ "readline", + \ "stream", + \ "string_decoder", + \ "tls", + \ "tty", + \ "dgram", + \ "url", + \ "util", + \ "v8", + \ "vm", + \ "zlib" ] + + " There's no source file for built-in node modules. + " Example: var http = require('http'); + if index(built_ins, a:module) != -1 + return 0 + endif + + " Handling absolute and relative paths. + " Example: var foo = require('./foo.js'); + if a:module =~ '^\/' || a:module =~ '^\.\{1,2}\/' + let root = fnamemodify(substitute(finddir("node_modules", ".;"), '/node_modules', '', ''), ':p:h:h') + if a:module =~ '^\.\{1,2}\/' + let module = substitute(a:module, '^\.\{1,2}\/', '', '') + endif + + let filename = 0 + try + let filename = findfile(module, root) + catch + try + let filename = findfile(module . ".js", root) + catch + try + let filename = findfile(module . "/index.js", root) + catch + let filename = 0 + endtry + endtry + endtry + + return filename + endif + + " Handling vendored-in modules. + " Example: var _ = require('lodash'); + for dir in NODE_MODULES_PATHS() + " require('module') => node_modules/module/package.json#main => node_modules/module/**/... + if filereadable(dir . "/" . a:module . "/package.json") + let package = json_decode(join(readfile(dir . "/" . a:module . "/package.json"))) + return dir . "/" . a:module . "/" . substitute(get(package, "main", "index.js"), '^\.\{1,2}\/', '', '') + endif + + " require('module') => node_modules/module/index.js + if filereadable(dir . "/" . a:module . "/index.js") + return dir . "/" . a:module . "/index.js" + endif + + " require('module') => node_modules/module.js + if filereadable(dir . "/" . a:module . ".js") + return dir . "/" . a:module . ".js" + endif + endfor + + " well, well, well + return 0 +endfunction + +function! NODE_MODULES_PATHS() abort + " node_modules/ + let node_modules = finddir("node_modules", ".;") + + " node_modules/foo/node_modules/ + let basic_dirs = extend([node_modules], globpath(node_modules, "*/node_modules", 1, 1)) + + " node_modules/@foo/bar/node_modules/ + let all_dirs = extend(basic_dirs, globpath(node_modules, "@*/*/node_modules", 1, 1)) + + return all_dirs +endfunction diff --git a/after/ftplugin/netrw.vim b/after/ftplugin/netrw.vim new file mode 100644 index 0000000..6864fbc --- /dev/null +++ b/after/ftplugin/netrw.vim @@ -0,0 +1 @@ +setl bufhidden=hide diff --git a/after/ftplugin/php.lua b/after/ftplugin/php.lua deleted file mode 100644 index cb80682..0000000 --- a/after/ftplugin/php.lua +++ /dev/null @@ -1,62 +0,0 @@ --- PHP-specific settings and enhancements --- Loaded automatically for PHP files - --- Enable includeexpr for intelligent gf (goto file) behavior --- Handles common WordPress/PHP path patterns like: --- require_once __DIR__ . '/../path/to/file.php'; --- include __FILE__ . '/relative/path.php'; -vim.opt_local.includeexpr = "v:lua.resolve_php_gf_path(v:fname)" - --- Global function to resolve PHP file paths for gf command -function _G.resolve_php_gf_path(fname) - local line = vim.api.nvim_get_current_line() - local current_dir = vim.fn.expand('%:p:h') - local current_file = vim.fn.expand('%:p') - - -- Pattern 1: __DIR__ . '/path' or __DIR__ . '/../path' - -- Most common in modern PHP/WordPress - local path = line:match("__DIR__%s*%.%s*['\"]([^'\"]+)['\"]") - if path then - path = current_dir .. path - return vim.fn.simplify(path) - end - - -- Pattern 2: __FILE__ . '/path' - -- Less common but appears in legacy WordPress code - -- __FILE__ resolves to the current file's full path, so we use its directory - path = line:match("__FILE__%s*%.%s*['\"]([^'\"]+)['\"]") - if path then - -- __FILE__ is the file itself, but when concatenated with a path, - -- it's typically used like __DIR__, so we use the directory - path = current_dir .. path - return vim.fn.simplify(path) - end - - -- Pattern 3: dirname(__FILE__) . '/path' - -- Old-style equivalent to __DIR__ - path = line:match("dirname%s*%(%s*__FILE__%s*%)%s*%.%s*['\"]([^'\"]+)['\"]") - if path then - path = current_dir .. path - return vim.fn.simplify(path) - end - - -- Pattern 4: Simple quoted path in require/include statements - -- Fallback for basic relative paths - path = line:match("require[_%w]*%s*['\"]([^'\"]+)['\"]") - if path then - -- Try relative to current file's directory - path = current_dir .. '/' .. path - return vim.fn.simplify(path) - end - - path = line:match("include[_%w]*%s*['\"]([^'\"]+)['\"]") - if path then - -- Try relative to current file's directory - path = current_dir .. '/' .. path - return vim.fn.simplify(path) - end - - -- Fallback: return as-is (normal gf behavior) - -- This allows standard gf to work for simple filenames - return fname -end diff --git a/after/ftplugin/php.vim b/after/ftplugin/php.vim new file mode 100644 index 0000000..9787fb3 --- /dev/null +++ b/after/ftplugin/php.vim @@ -0,0 +1,2 @@ +setlocal iskeyword+=$ +setlocal autoindent diff --git a/after/ftplugin/python.vim b/after/ftplugin/python.vim new file mode 100644 index 0000000..de126ac --- /dev/null +++ b/after/ftplugin/python.vim @@ -0,0 +1,11 @@ +setlocal tabstop=4 + +setlocal textwidth=88 + +setlocal foldmethod=indent +setlocal foldnestmax=1 + +setlocal colorcolumn=88 + +noremap :w:silent !clear;python % :redraw! +nnoremap :call SaveAndExecute('python') diff --git a/after/ftplugin/qf.vim b/after/ftplugin/qf.vim new file mode 100644 index 0000000..78fb903 --- /dev/null +++ b/after/ftplugin/qf.vim @@ -0,0 +1,2 @@ +nmap o +nmap q :q diff --git a/after/ftplugin/sass.vim b/after/ftplugin/sass.vim new file mode 100644 index 0000000..d19ac0e --- /dev/null +++ b/after/ftplugin/sass.vim @@ -0,0 +1 @@ +setlocal includeexpr=substitute(substitute(substitute(v:fname,'\%(.*/\|^\)\zs','_',''),'^[\\~@]\/','./',''),'^[\\~@]','./node_modules/','') diff --git a/after/ftplugin/vim.vim b/after/ftplugin/vim.vim new file mode 100644 index 0000000..57b1e2e --- /dev/null +++ b/after/ftplugin/vim.vim @@ -0,0 +1,2 @@ +setlocal foldmethod=marker + diff --git a/after/indent/php.vim b/after/indent/php.vim new file mode 100644 index 0000000..2d98542 --- /dev/null +++ b/after/indent/php.vim @@ -0,0 +1,4 @@ +" https://github.com/nvim-treesitter/nvim-treesitter/issues/462#issuecomment-700278736 +setlocal indentexpr = +setlocal autoindent +setlocal smartindent diff --git a/after/queries/bash/folds.scm b/after/queries/bash/folds.scm deleted file mode 100644 index 30a154e..0000000 --- a/after/queries/bash/folds.scm +++ /dev/null @@ -1,4 +0,0 @@ -;; extends - -;; Fold comment blocks -(comment) @fold diff --git a/after/queries/css/folds.scm b/after/queries/css/folds.scm deleted file mode 100644 index 30a154e..0000000 --- a/after/queries/css/folds.scm +++ /dev/null @@ -1,4 +0,0 @@ -;; extends - -;; Fold comment blocks -(comment) @fold diff --git a/after/queries/css/highlights.scm b/after/queries/css/highlights.scm index 8409fff..7fa2000 100644 --- a/after/queries/css/highlights.scm +++ b/after/queries/css/highlights.scm @@ -1,42 +1,18 @@ -;extends - -; CSS Selectors - ID selectors (#my-id) -; Priority: Must override default @constant capture -(id_selector "#" @punctuation.delimiter) -(id_selector (id_name) @CssIdentifier (#set! priority 200)) - -; CSS Selectors - Class selectors (.my-class) -(class_selector "." @punctuation.delimiter) -(class_selector (class_name) @CssClassName (#set! priority 200)) - -; CSS Selectors - Pseudo-class selectors (:hover, :focus, etc.) -(pseudo_class_selector ":" @punctuation.delimiter) -(pseudo_class_selector (class_name) @cssPseudoClass (#set! priority 200)) - -; CSS Selectors - Pseudo-element selectors (::before, ::after) -(pseudo_element_selector "::" @punctuation.delimiter) -(pseudo_element_selector (tag_name) @cssPseudoElement (#set! priority 200)) - -; CSS Selectors - Nesting selector (&) -(nesting_selector) @cssNestingSelector - -; CSS Selectors - Universal selector (*) -(universal_selector) @CssUniversalSelector - -; CSS Selectors - Tag/element selectors (div, p, etc.) +(id_selector (id_name) @CssIdentifier) +(id_selector (id_name)) @CssIdSelector (tag_name) @HtmlTagName -; CSS Properties -((property_name) @CssProp) +(class_selector (class_name) @CssClassName) +(selectors (pseudo_class_selector (class_name) @cssPseudoClass)) +(nesting_selector) @cssNestingSelector -; CSS Property values -(declaration (property_name) (_) @CssPropertyValue) +; need to find out how to make this more specific? +(universal_selector) @CssUniversalSelector + +((property_name) (_)) @CssProp -; CSS Units (px, em, rem, %, etc.) (unit) @CssUnit -; CSS Media queries -(media_statement - (feature_query - (feature_name) @cssMediaFeatureName - (_ (unit) @cssMediaQueryValueUnit) @cssMediaQueryValue) @cssMediaQuery) +(declaration (property_name) (_) @CssPropertyValue) + +(media_statement (feature_query (feature_name) @cssMediaFeatureName (_ (unit) @cssMediaQueryValueUnit) @cssMediaQueryValue) @cssMediaQuery) diff --git a/after/queries/ecma/highlights.scm b/after/queries/ecma/highlights.scm new file mode 100644 index 0000000..e69de29 diff --git a/after/queries/html/folds.scm b/after/queries/html/folds.scm deleted file mode 100644 index 30a154e..0000000 --- a/after/queries/html/folds.scm +++ /dev/null @@ -1,4 +0,0 @@ -;; extends - -;; Fold comment blocks -(comment) @fold diff --git a/after/queries/html/highlights.scm b/after/queries/html/highlights.scm index 998bdc3..2b752d4 100644 --- a/after/queries/html/highlights.scm +++ b/after/queries/html/highlights.scm @@ -1,20 +1,17 @@ -;extends +(start_tag + (attribute + (attribute_name) @ClassNameAttribute (#eq? @ClassNameAttribute "class") + (quoted_attribute_value + (attribute_value) @CssClassName ))) -; HTML class attribute values - should match CSS .class-name color -; Priority: Must override default @string capture (priority 99) -(attribute - (attribute_name) @ClassNameAttribute (#eq? @ClassNameAttribute "class") - (quoted_attribute_value - (attribute_value) @CssClassName (#set! priority 200))) +(start_tag + (attribute + (attribute_name) @IdAttribute (#eq? @IdAttribute "id") + (quoted_attribute_value + (attribute_value) @CssIdentifier ))) -; HTML id attribute values - should match CSS #id-name color -(attribute - (attribute_name) @IdAttribute (#eq? @IdAttribute "id") - (quoted_attribute_value - (attribute_value) @CssIdentifier (#set! priority 200))) - -; HTML data-* attributes -(attribute - (attribute_name) @DataAttribute (#match? @DataAttribute "^data-") - (quoted_attribute_value - (attribute_value) @DataAttributeValue (#set! priority 200))) +(start_tag + (attribute + (attribute_name) @DataAttribute (#match? @DataAttribute "^data-") + (quoted_attribute_value + (attribute_value) @DataAttributeValue ))) diff --git a/after/queries/javascript/folds.scm b/after/queries/javascript/folds.scm deleted file mode 100644 index c56348f..0000000 --- a/after/queries/javascript/folds.scm +++ /dev/null @@ -1,8 +0,0 @@ -;; extends - -;; Fold comment blocks (including consecutive single-line comments) -(comment) @fold - -;; Fold consecutive single-line comments as a block -((comment) @fold - (#match? @fold "^//")) diff --git a/after/queries/lua/folds.scm b/after/queries/lua/folds.scm deleted file mode 100644 index 30a154e..0000000 --- a/after/queries/lua/folds.scm +++ /dev/null @@ -1,4 +0,0 @@ -;; extends - -;; Fold comment blocks -(comment) @fold diff --git a/after/queries/php/folds.scm b/after/queries/php/folds.scm deleted file mode 100644 index 57f8cae..0000000 --- a/after/queries/php/folds.scm +++ /dev/null @@ -1,4 +0,0 @@ -;; extends - -;; Fold comment blocks (including /** */ docblocks) -(comment) @fold diff --git a/after/queries/python/folds.scm b/after/queries/python/folds.scm deleted file mode 100644 index 30a154e..0000000 --- a/after/queries/python/folds.scm +++ /dev/null @@ -1,4 +0,0 @@ -;; extends - -;; Fold comment blocks -(comment) @fold diff --git a/after/queries/scss/folds.scm b/after/queries/scss/folds.scm deleted file mode 100644 index 30a154e..0000000 --- a/after/queries/scss/folds.scm +++ /dev/null @@ -1,4 +0,0 @@ -;; extends - -;; Fold comment blocks -(comment) @fold diff --git a/after/queries/tsx/folds.scm b/after/queries/tsx/folds.scm deleted file mode 100644 index 30a154e..0000000 --- a/after/queries/tsx/folds.scm +++ /dev/null @@ -1,4 +0,0 @@ -;; extends - -;; Fold comment blocks -(comment) @fold diff --git a/after/queries/typescript/folds.scm b/after/queries/typescript/folds.scm deleted file mode 100644 index 30a154e..0000000 --- a/after/queries/typescript/folds.scm +++ /dev/null @@ -1,4 +0,0 @@ -;; extends - -;; Fold comment blocks -(comment) @fold diff --git a/after/queries/vim/folds.scm b/after/queries/vim/folds.scm deleted file mode 100644 index 30a154e..0000000 --- a/after/queries/vim/folds.scm +++ /dev/null @@ -1,4 +0,0 @@ -;; extends - -;; Fold comment blocks -(comment) @fold diff --git a/colors/README.txt b/colors/README.txt new file mode 100644 index 0000000..8fa6f32 --- /dev/null +++ b/colors/README.txt @@ -0,0 +1,79 @@ +README.txt for color scheme files + +These files are used for the ":colorscheme" command. They appear in the +Edit/Color Scheme menu in the GUI. + + +Hints for writing a color scheme file: + +There are two basic ways to define a color scheme: + +1. Define a new Normal color and set the 'background' option accordingly. + set background={light or dark} + highlight clear + highlight Normal ... + ... + +2. Use the default Normal color and automatically adjust to the value of + 'background'. + highlight clear Normal + set background& + highlight clear + if &background == "light" + highlight Error ... + ... + else + highlight Error ... + ... + endif + +You can use ":highlight clear" to reset everything to the defaults, and then +change the groups that you want differently. This also will work for groups +that are added in later versions of Vim. +Note that ":highlight clear" uses the value of 'background', thus set it +before this command. +Some attributes (e.g., bold) might be set in the defaults that you want +removed in your color scheme. Use something like "gui=NONE" to remove the +attributes. + +In case you want to set 'background' depending on the colorscheme selected, +this autocmd might be useful: + autocmd SourcePre */colors/blue_sky.vim set background=dark +Replace "blue_sky" with the name of the colorscheme. + +In case you want to tweak a colorscheme after it was loaded, check out the +ColorScheme autocmd event. + +To customize a colorscheme use another name, e.g. "~/.vim/colors/mine.vim", +and use `:runtime` to load the original colorscheme: + " load the "evening" colorscheme + runtime colors/evening.vim + " change the color of statements + hi Statement ctermfg=Blue guifg=Blue + +To see which highlight group is used where, find the help for +"highlight-groups" and "group-name". + +You can use ":highlight" to find out the current colors. Exception: the +ctermfg and ctermbg values are numbers, which are only valid for the current +terminal. Use the color names instead. See ":help cterm-colors". + +The default color settings can be found in the source file src/syntax.c. +Search for "highlight_init". + +If you think you have a color scheme that is good enough to be used by others, +please check the following items: + +- Does it work in a color terminal as well as in the GUI? +- Is "g:colors_name" set to a meaningful value? In case of doubt you can do + it this way: + let g:colors_name = expand(':t:r') +- Is 'background' either used or appropriately set to "light" or "dark"? +- Try setting 'hlsearch' and searching for a pattern, is the match easy to + spot? +- Split a window with ":split" and ":vsplit". Are the status lines and + vertical separators clearly visible? +- In the GUI, is it easy to find the cursor, also in a file with lots of + syntax highlighting? +- Do not use hard coded escape sequences, these will not work in other + terminals. Always use color names or #RRGGBB for the GUI. diff --git a/colors/paper-tonic-modern.lua b/colors/paper-tonic-modern.lua deleted file mode 100644 index d6179e5..0000000 --- a/colors/paper-tonic-modern.lua +++ /dev/null @@ -1,20 +0,0 @@ --- Paper Tonic Modern --- A paper-like colorscheme for Neovim supporting both light and dark modes --- Forked from the original Paper Tonic with modern Lua implementation - --- Reset highlights and syntax -vim.cmd('highlight clear') -if vim.fn.exists('syntax_on') then - vim.cmd('syntax reset') -end - --- Set colorscheme name -vim.g.colors_name = 'paper-tonic-modern' - --- Set default background if not already set -if vim.o.background == '' then - vim.o.background = 'light' -end - --- Load the colorscheme -require('paper-tonic-modern').load() diff --git a/ftdetect/astro.vim b/ftdetect/astro.vim new file mode 100644 index 0000000..4fe142e --- /dev/null +++ b/ftdetect/astro.vim @@ -0,0 +1 @@ +autocmd BufRead,BufEnter *.astro set filetype=astro diff --git a/ftplugin/css.vim b/ftplugin/css.vim new file mode 100644 index 0000000..df4fe48 --- /dev/null +++ b/ftplugin/css.vim @@ -0,0 +1 @@ +setlocal iskeyword+=- diff --git a/ftplugin/eruby.vim b/ftplugin/eruby.vim new file mode 100644 index 0000000..3211e37 --- /dev/null +++ b/ftplugin/eruby.vim @@ -0,0 +1,2 @@ +nnoremap :call ft#compileeruby#CompileEruby(0) +nnoremap :call ft#compileeruby#CompileEruby(1) diff --git a/ftplugin/fish.vim b/ftplugin/fish.vim new file mode 100644 index 0000000..0528a65 --- /dev/null +++ b/ftplugin/fish.vim @@ -0,0 +1 @@ +:compiler fish diff --git a/ftplugin/help.vim b/ftplugin/help.vim new file mode 100644 index 0000000..24dd22c --- /dev/null +++ b/ftplugin/help.vim @@ -0,0 +1 @@ +setlocal keywordprg=:help diff --git a/ftplugin/html.vim b/ftplugin/html.vim new file mode 100644 index 0000000..e69de29 diff --git a/ftplugin/javascript.vim b/ftplugin/javascript.vim new file mode 100644 index 0000000..fc6035c --- /dev/null +++ b/ftplugin/javascript.vim @@ -0,0 +1 @@ +setlocal iskeyword+=$ diff --git a/ftplugin/markdown.vim b/ftplugin/markdown.vim new file mode 100644 index 0000000..fedb364 --- /dev/null +++ b/ftplugin/markdown.vim @@ -0,0 +1,20 @@ +setlocal spell + +" markdown : jump to next heading +" https://gist.github.com/romainl/ac63e108c3d11084be62b3c04156c263 +function! s:JumpToNextHeading(direction, count) + let col = col(".") + + silent execute a:direction == "up" ? '?^#' : '/^#' + + if a:count > 1 + silent execute "normal! " . repeat("n", a:direction == "up" && col != 1 ? a:count : a:count - 1) + endif + + silent execute "normal! " . col . "|" + + unlet col +endfunction + +nnoremap ]] :call JumpToNextHeading("down", v:count1) +nnoremap [[ :call JumpToNextHeading("up", v:count1) diff --git a/ftplugin/octobercms.vim b/ftplugin/octobercms.vim new file mode 100644 index 0000000..6335705 --- /dev/null +++ b/ftplugin/octobercms.vim @@ -0,0 +1,8 @@ +function! StripSpecialM() abort + :%s/ $//e +endfunction + +augroup RemoveSpecialM + autocmd BufWritePre call StripSpecialM() +augroup END + diff --git a/ftplugin/ruby.vim b/ftplugin/ruby.vim new file mode 100644 index 0000000..2313f49 --- /dev/null +++ b/ftplugin/ruby.vim @@ -0,0 +1,2 @@ +nnoremap :call SaveAndExecute('ruby') + diff --git a/ftplugin/sass.vim b/ftplugin/sass.vim new file mode 100644 index 0000000..fc6035c --- /dev/null +++ b/ftplugin/sass.vim @@ -0,0 +1 @@ +setlocal iskeyword+=$ diff --git a/ftplugin/sh.vim b/ftplugin/sh.vim new file mode 100644 index 0000000..2151ea5 --- /dev/null +++ b/ftplugin/sh.vim @@ -0,0 +1,2 @@ +setlocal makeprg=shellcheck\ -f\ gcc\ % +nnoremap :w !sh diff --git a/ftplugin/vim.vim b/ftplugin/vim.vim new file mode 100644 index 0000000..385d996 --- /dev/null +++ b/ftplugin/vim.vim @@ -0,0 +1,4 @@ +setlocal keywordprg=:help +setlocal iskeyword+=: + +nnoremap :w \| source % diff --git a/ftplugin/vue.vim b/ftplugin/vue.vim new file mode 100644 index 0000000..5325c8c --- /dev/null +++ b/ftplugin/vue.vim @@ -0,0 +1,8 @@ +setlocal includeexpr=substitute(substitute(v:fname,'^[\\~@]\/','./',''),'^[\\~@]','./node_modules/','') + +setlocal suffixesadd=.js,.vue,.scss +setlocal complete=.,w,b,u,i + +setlocal include=\\%(\\[^;\"']*\\)[\"']\\zs[^\"']* + +setlocal foldnestmax=3 diff --git a/init.auto-window.vim b/init.auto-window.vim new file mode 100644 index 0000000..c587477 --- /dev/null +++ b/init.auto-window.vim @@ -0,0 +1,34 @@ +"auto_window_settings {{{ +function! OnWinEnter() abort"{{{ + if &buftype != '' + setlocal colorcolumn=0 + elseif exists('b:colorcolumn_restore') + execute 'setlocal colorcolumn=' . b:colorcolumn_restore + endif + if &buftype == 'terminal' + setlocal nonumber norelativenumber + else + setlocal number relativenumber + endif + setlocal cursorline + setlocal cursorcolumn +endfunction + +"}}} +function! OnWinLeave() abort"{{{ + let b:colorcolumn_restore = &colorcolumn + setlocal colorcolumn=0 + setlocal nocursorline + setlocal nocursorcolumn + setlocal norelativenumber +endfunction + +"}}} +augroup auto_window_settings "{{{ + autocmd! + autocmd WinEnter * call OnWinEnter() + autocmd WinLeave * call OnWinLeave() +augroup END +"}}} augroup auto_window_settings +" }}} auto_window_settings + diff --git a/init.commands.vim b/init.commands.vim new file mode 100644 index 0000000..418e83d --- /dev/null +++ b/init.commands.vim @@ -0,0 +1,27 @@ +" SpacesToTabs {{{ +" TODO - ake a proper regex substitution +function! s:spacestotabs() + %s/^ / /e + %s/^ / /e + %s/^ / /e + %s/^ / /e + %s/^ / /e + %s/^ / /e +endfunction +command SpacesToTabs call s:spacestotabs() + + +"}}} +" TrimWhitespace {{{ +command! -range=% TrimWhitespace let b:wv = winsaveview() | + \ keeppattern ,s/\s\+$// | + \ call winrestview(b:wv) + + +"}}} +" Scratch, ScratchVertical {{{ +command! Scratch new | setlocal buftype=nofile | setlocal bufhidden=hide | setlocal noswapfile +command! ScratchVertical vnew | setlocal buftype=nofile | setlocal bufhidden=hide | setlocal noswapfile +"}}} +" +" diff --git a/init.fold-text.vim b/init.fold-text.vim new file mode 100644 index 0000000..a8994b1 --- /dev/null +++ b/init.fold-text.vim @@ -0,0 +1,52 @@ +function! MyFoldText() + if !exists('g:foldtext_column') + let g:foldtext_column = 80 " column to right align foldtext with + endif + + if !exists('b:foldtext_column') + let b:foldtext_column = g:foldtext_column " column to right align foldtext with + endif + + if !exists('g:foldtext_maxcolumn') + let g:foldtext_maxcolumn = 120 + endif + + let l:linecount = v:foldend - v:foldstart + " don't display foldmarker braces + " put one of the braces in brackets so vim doesn't treat + " it as an actual fold marker + let l:line = substitute(getline(v:foldstart), '"\?{\({\){', '', '') + " don't display vim comment quotation marks + " TODO other comment markers + let l:line = substitute(l:line, "\^\"\\s\\?", '', '') + " TODO replace spaces with tabs if appropriate + + " replace tabs with spaces if expandtab + if &expandtab == 0 + let l:tabwidth = &tabstop + let l:tabspace = ' '[1:l:tabwidth] + let l:line = substitute(l:line, ' ', l:tabspace, 'g') + endif + + " let l:postfix = l:linecount . ' ' . substitute(v:folddashes, '-', '•', 'g') + let l:postfix = l:linecount . ' ' . substitute(v:folddashes, '-', '↓', 'g') + while strchars(l:postfix) < 7 + let l:postfix = ' ' . l:postfix + endwhile + " let l:postfix = ' ↓ ' . l:postfix + + let l:len_line = len(l:line) + let l:len_postfix = strchars(l:postfix) + + if l:len_line + l:len_postfix <= b:foldtext_column + let l:padding = ' '[l:len_line + l:len_postfix + 0:b:foldtext_column - 1] + let l:foldtext = l:line . l:padding . l:postfix + else + let l:sniptext = ' ⋯' + let l:foldtext = l:line[:b:foldtext_column - 1 - strchars(l:sniptext) - l:len_postfix] . l:sniptext . l:postfix + endif + + return l:foldtext +endfunction + +set foldtext=MyFoldText() diff --git a/init.full.vim b/init.full.vim new file mode 100644 index 0000000..dd80039 --- /dev/null +++ b/init.full.vim @@ -0,0 +1,434 @@ +" set ruby program to global one. Need to investigate if this will cause +" problems if I ever use ruby virtual environments or RVM or similar. +let g:ruby_host_prog = '~/.gem/ruby/2.7.0/bin/neovim-ruby-host' + +source ~/.config/nvim/init.plugins.vim +source ~/.config/nvim/init.tabline.vim +source ~/.config/nvim/init.auto-window.vim +source ~/.config/nvim/init.fold-text.vim +source ~/.config/nvim/init.commands.vim +" +" require lua init modules +lua <SynStack()"{{{ + if !exists('*synstack') + return + endif + echo map(synstack(line('.'), col('.')), 'synIDattr(v:val,"name")') '-> ' . synIDattr(synIDtrans(synID(line('.'),col('.'),1)), 'name' ) +endfunc +" nmap pp :call SynStack() +nmap pp :TSHighlightCapturesUnderCursor +"}}} +function! s:RunShellCommand(cmdline) abort"{{{ + " Shell command + " http://vim.wikia.com/wiki/VimTip1599 + + let l:expanded_cmdline = a:cmdline + for l:part in split(a:cmdline, ' ') + if l:part[0] =~ '\v[%#<]' + let l:expanded_part = fnameescape(expand(l:part)) + let l:expanded_cmdline = substitute(l:expanded_cmdline, l:part, l:expanded_part, '') + endif + endfor + + if g:shell_scratch_buffer_nr > -1 + let l:win_nr = bufwinnr(g:shell_scratch_buffer_nr) + if l:win_nr < 0 + execute 'bdelete' g:shell_scratch_buffer_nr + top new + let g:shell_scratch_buffer_nr = bufnr('%') + else + execute l:win_nr. ' wincmd w' + setlocal modifiable + %delete _ + endif + else + top new + let g:shell_scratch_buffer_nr = bufnr('%') + endif + + setlocal buftype=nofile bufhidden=wipe nobuflisted noswapfile nowrap + nnoremap q :bdelete + augroup ResetShellBufferNr + autocmd! * + autocmd BufUnload let g:shell_scratch_buffer_nr = -1 + augroup END + + " call setline(1, 'You entered: ' . a:cmdline) + " call setline(2, 'Expanded Form: ' .l:expanded_cmdline) + " call setline(3,substitute(getline(2),'.','=','g')) + execute '$read !'. l:expanded_cmdline + 1 + + setlocal nomodifiable + if !exists('b:shell_line_count') + let b:shell_line_count = line('$') + if b:shell_line_count > 25 + let b:shell_line_count = 20 + endif + execute 'resize' b:shell_line_count + 1 + endif + + wincmd p +endfunction + +command! -complete=shellcmd -nargs=+ Shell call s:RunShellCommand() +let g:shell_scratch_buffer_nr = -1 + +"}}} +function! SaveAndExecute(ex_command) abort "{{{ + " https://stackoverflow.com/a/40195855 + " ex_command: command to run to execute file + " SOURCE [reusable window]: https://github.com/fatih/vim-go/blob/master/autoload/go/ui.vim + + " save and reload current file + silent execute 'update | edit' + + " get file path of current file + let s:current_buffer_file_path = expand('%') + + let s:output_buffer_name = 'Output' + let s:output_buffer_filetype = 'output' + + " reuse existing buffer window if it exists otherwise create a new one + if !exists('c:buf_nr') || !bufexists(s:buf_nr) || bufwinnr(s:buf_nr) == -1 + silent execute 'top new ' . s:output_buffer_name + let s:buf_nr = bufnr('%') + elseif bufwinnr(s:buf_nr) != bufwinnr('%') + silent execute bufwinnr(s:buf_nr) . 'wincmd w' + endif + + silent execute 'setlocal filetype=' . s:output_buffer_filetype + setlocal bufhidden=delete + setlocal buftype=nofile + setlocal noswapfile + setlocal nobuflisted + setlocal winfixheight + setlocal cursorline " make it easy to distinguish + " setlocal nonumber + " setlocal norelativenumber + setlocal showbreak="" + + nnoremap q :bdelete!'.zz + + " clear the buffer + setlocal noreadonly + " setlocal modifiable + %delete _ + + " add the console output + silent execute '.!'. a:ex_command . ' ' . shellescape(s:current_buffer_file_path, 1) + + " resize window to content length + " Note: This is annoying because if you print a lot of lines then your code buffer is forced to a height of one line every time you run this function. + " However without this line the buffer starts off as a default size and if you resize the buffer then it keeps that custom size after repeated runs of this function. + " But if you close the output buffer then it returns to using the default size when its recreated + "execute 'resize' . line('$') + + " make the buffer non modifiable + setlocal readonly + " setlocal nomodifiable +endfunction + +"}}} +function! JsIncludeExpr(file)"{{{ + " substitute(substitute(v:fname,'^[\\~@]\/','./',''),'^[\\~@]','./node_modules/','') + return substitute(substitute(a:file,'^[\\~@]\/','./',''),'^[\\~@]','./node_modules/','') + +endfunction + +"}}} +function! Redir(cmd) "{{{ + for win in range(1, winnr('$')) + if getwinvar(win, 'scratch') + execute win . 'windo close' + endif + endfor + if a:cmd =~ '^!' + let output = system(matchstr(a:cmd, '^!\zs.*')) + else + redir => output + execute a:cmd + redir END + endif + vnew + let w:scratch = 1 + setlocal buftype=nofile bufhidden=wipe nobuflisted noswapfile + call setline(1, split(output, "\n")) +endfunction + +command! -nargs=1 -complete=command Redir silent call Redir() +" Usage: +" :Redir hi ............. show the full output of command ':hi' in a scratch window +" :Redir !ls -al ........ show the full output of command ':!ls -al' in a scratch window +"}}} +"}}} +function! ToggleHighlights() abort "{{{ + if ! exists('b:toggle_highlights_state') + " state 1 is normal, state 0 is faded + let b:toggle_highlights_state = 1 + else + let b:toggle_highlights_state = ! b:toggle_highlights_state + endif + + if b:toggle_highlights_state == 1 + hi! link Comment None + else + hi! link Comment CommentDim + endif +endfunction +"}}} +"----------------------------------------------------------------------------}}} +" #settings {{{ + +scriptencoding utf-8 +set ttyfast + +set dictionary=spell +" set thesaurus+=/usr/share/dict/mthesaur.txt +augroup Dictionary + au! + au FileType markdown,text setlocal dictionary=/usr/share/dict/aspell-dump.txt +augroup END + +" disable background color erase +" https://sunaku.github.io/vim-256color-bce.html +set t_ut= + +syntax on +set fillchars=stl:\ ,stlnc:\ ,vert:\|,fold:\ + +set guioptions-=mTrLb +" set guioptions+=c + +if exists('+termguicolors') + let &t_8f = "\[38;2;%lu;%lu;%lum" + let &t_8b = "\[48;2;%lu;%lu;%lum" + set termguicolors +endif + +colorscheme paper-tonic + +set updatetime=100 +set timeoutlen=500 +set lazyredraw + +" https://parceljs.org/hmr.html#safe-write +set backupcopy=yes + +set title + +" the ;/home/* tells vim to stop searching at /home/* (I hope!) +set tags=./.tags,.tags,./tags-external,.tags-external;/home/* + +" persisitent undo file +set undofile +set undodir=~/.config/nvim/undodir +set backupdir=~/.nvim/tmpdir +set directory=~/.nvim/tmpdir + +set viewoptions-=options + +set nosplitbelow nosplitright +set switchbuf=uselast + +set ignorecase +set smartcase + +set wildmenu +set wildmode=longest:full,full +set wildignore+=**/node_modules/**,**/dist/**,**/.git/**,**/build/** + +" Use ag over grep +if executable('ag') + set grepprg=ag\ --nogroup\ --nocolor\ --ignore\ node_modules +endif + +set hidden + +set hlsearch + +set completeopt=menuone,noselect + +set nospell +set spelllang=en_gb + +set diffopt+=vertical + +let g:tex_flavor = 'latex' + +set rnu nu + +set tabstop=2 +set softtabstop=-1 +set shiftwidth=0 +set shiftround +set noexpandtab + +set autoindent +set breakindent +set showbreak=\ \ ↳\ + +set formatoptions=cq +set wrapmargin=0 + +setlocal cursorline + +set foldcolumn=0 +set signcolumn=yes +set colorcolumn=80,120 + +set iskeyword+=- +set scrolloff=4 +set scrolljump=4 +set showcmd + +set incsearch +set inccommand=nosplit + +set laststatus=2 +set shortmess=aoOT +set cmdheight=3 + +set foldnestmax=9 +set foldlevelstart=99 + +set showmode + +set mouse=a + +let g:netrw_preview = 1 + +set listchars=eol:¬,tab:│\ ,trail:~,extends:>,precedes:<,space:· +set fillchars=stl:\ ,stlnc:\ ,vert:┃,fold:\ + +set statusline=\ +" buffer number +set statusline+=[%n]\ \ +" line of total_lines and percentage through file +set statusline+=%-20(%l\ of\ %L\ (%p%%)%) +" column, virtual column +set statusline+=%-10(:%c\ %((%V)%)%) +" separator, highlight color +set statusline+=%=%#StatusLineNC# +" CoC status +if exists('*coc#exists') + set statusline+=%{coc#status()} +endif +" separator +set statusline+=%=%#StatusLine# +set statusline+=%y\ +set statusline+=%r\ %m\ +set statusline+=%{&buftype==''?expand('%f'):''} +set statusline+=\ + +set conceallevel=0 +"----------------------------------------------------------------------------}}} +" #mappings {{{ +let g:mapleader = ' ' +" miscallaneous {{{ +nnoremap l :colorscheme paper-tonic +nnoremap d :colorscheme monotonous-dark +nnoremap 0 ^ +nnoremap cs :let @/="" +nnoremap nh (&hls && v:hlsearch ? ':nohls' : ':set hls')."\n" +" Focus on current fold, close the rest +nnoremap zz zMzvzt +" open quickfix window of TODOs +nnoremap td :grep -RE '(TODO\\|FIXME)' .:botright cwindow:echo len(getqflist()) 'TODOs' +" sync highlighting from start + +"}}} +" location list and quickfix mappings {{{ +nnoremap lo :botright lwindow +nnoremap :lprevzv +nnoremap :lnextzv +nnoremap lc :lclose +nnoremap lh :lhistory +nnoremap lp :lolder +nnoremap ln :lnewer + +nnoremap qo :botright cwindow +nnoremap :cprevzv +nnoremap :cnextzv +nnoremap qc :cclose +nnoremap qh :chistory +nnoremap qp :colder +nnoremap qn :cnewer + +nnoremap qt :tabnew \| cwindow + +"}}} +"----------------------------------------------------------------------------}}} +" #abbreviations {{{ + +iabbrev adn and +iabbrev waht what +iabbrev tehn then +iabbrev functin function +iabbrev positin position + +"----------------------------------------------------------------------------}}} +" #autocommands {{{ + +" template files {{{ +augroup Templates + autocmd! + autocmd BufNewFile *.sh 0read ~/.config/nvim/templates/template.sh | normal G + autocmd BufNewFile *.html 0read ~/.config/nvim/templates/template.html | normal gg + autocmd BufNewFile *.css 0read ~/.config/nvim/templates/template.css | normal G + autocmd BufNewFile *.scss 0read ~/.config/nvim/templates/template.css | normal G +augroup END + +" }}} +" persistent folds {{{ +augroup AutoSaveFolds + autocmd! + autocmd BufWrite ?* mkview + autocmd BufRead ?* silent! loadview +augroup END + +" }}} +" Show trailing whitepace and spaces before a tab: {{{ +augroup ShowWhiteSpaceErrors + autocmd! + autocmd Syntax * syn match ExtraWhitespace /\s\+$\| \+\ze\t/ containedin=ALL +augroup END + +" }}} + +" Automatically reload .vimrc if changed {{{ +augroup ReloadVimrc + autocmd! + autocmd BufWritePost .vimrc,_vimrc,vimrc,.gvimrc,_gvimrc,gvimrc so $MYVIMRC | if has('gui_running') | so $MYGVIMRC | endif +augroup END + +" }}} +" Open quickfix window{{{ +" augroup QuickFixAutoload +" autocmd! +" autocmd QuickFixCmdPost [^l]* nested botright cwindow +" autocmd QuickFixCmdPost l* nested botright lwindow +" augroup END + +augroup OnTerminalOpen + autocmd! + autocmd TermOpen * setlocal nonumber norelativenumber +augroup END + +" }}} + +"----------------------------------------------------------------------------}}} +" +" +" require lua init +lua < + " - can use tab completion with this + " Parsers not on this list can be added manually + " + " If you update nvim-treesitter and want to make sure the parser is at the latest compatible version (as specified in nvim-treesitter's lockfile.json), use + " :TSUpdate {language}. + " To update all parsers unconditionally, use + " :TSUpdate all or just :TSUpdate. + " + " Each module provides a distinct tree-sitter-based feature such as highlighting, indentation, or folding; see :h nvim-treesitter-modules or "Available modules" below for a list of modules and their options. +" All modules are disabled by default and need to be activated explicitly in your init.vim +" +" Each module can also be enabled or disabled interactively through the following commands: +" :TSBufEnable {module} " enable module on current buffer +" :TSBufDisable {module} " disable module on current buffer +" :TSEnableAll {module} [{ft}] " enable module on every buffer. If filetype is specified, enable only for this filetype. +" :TSDisableAll {module} [{ft}] " disable module on every buffer. If filetype is specified, disable only for this filetype. +" :TSModuleInfo [{module}] " list information about modules state for each filetype +" +" Check :h nvim-treesitter-commands for a list of all available commands. It may be necessary to reload the buffer (e.g., via :e) after enabling a module interactively. + + "}}} +" #playground (temporary) {{{ + " https://github.com/nvim-treesitter/playground + " Plug 'nvim-treesitter/playground' + "}}} +" #vim-lspconfig {{{ + " https://github.com/neovim/nvim-lspconfig + " https://github.com/neovim/nvim-lspconfig/wiki + Plug 'neovim/nvim-lspconfig' + "}}} +" #plenary.nvim {{{ + " https://github.com/nvim-lua/plenary.nvim + " required for null-ls + Plug 'nvim-lua/plenary.nvim' + "}}} +" #null-ls.nvim {{{ + " https://github.com/jose-elias-alvarez/null-ls.nvim + Plug 'jose-elias-alvarez/null-ls.nvim' + "}}} +" #nvim-cmp {{{ + " https://github.com/hrsh7th/nvim-cmp/ + " completion + " Plug 'hrsh7th/nvim-cmp', { 'branch': 'main' } + " Plug 'hrsh7th/cmp-nvim-lsp', { 'branch': 'main' } + " Plug 'hrsh7th/cmp-buffer', { 'branch': 'main' } + " Plug 'hrsh7th/cmp-path', { 'branch': 'main' } + " Plug 'uga-rosa/cmp-dictionary', { 'branch': 'main' } + " let g:cmp_dictionary_exact = -1 + " Plug 'quangnguyen30192/cmp-nvim-ultisnips', { 'branch': 'main' } + + "}}} +" #indent-blankline.nvim {{{ + " https://github.com/lukas-reineke/indent-blankline.nvim + Plug 'lukas-reineke/indent-blankline.nvim' + "}}} + +" #iamcco/markdown-preview.nvim {{{ + " https://github.com/iamcco/markdown-preview.nvim + Plug 'iamcco/markdown-preview.nvim', { 'do': { -> mkdp#util#install() }, 'for': ['markdown', 'vim-plug']} + + let g:mkdp_browser = '/usr/local/bin/chromium-app' + let g:mkdp_echo_preview_url = 1 + nmap m MarkdownPreviewToggle + + " commands + " MarkdownPreview + " MarkdownPreviewStop + " MarkdownPreviewToggle + + "}}} + +" keeping +" #vim-hexokinase {{{ + " https://github.com/chrisbra/Colorizer + " display colors asynchronously + Plug 'chrisbra/Colorizer' + " let g:colorizer_use_virtual_text = 1 + nnoremap cc :ColorToggle + + "}}} +" #nvim-autopairs {{{ +" https://github.com/windwp/nvim-autopairs +" automatic quote, paranthesis,etc closing. + Plug 'windwp/nvim-autopairs' + "}}} + + +" #nvim-ts-autotag {{{ +" https://github.com/windwp/nvim-ts-autotag +" automatic html tag closing/renaming. +" Plug 'windwp/nvim-ts-autotag', { 'branch': 'main' } + + + "}}} +" #emmet-vim {{{ + " https://github.com/mattn/emmet-vim + Plug 'mattn/emmet-vim' + let g:user_emmet_leader_key=',,' + let g:user_emmet_settings = { + \ 'indentation': ' ', + \} + + "}}} +" #gitgutter {{{ + " https://github.com/airblade/vim-gitgutter/blob/master/README.mkd + " show git diff in sign column + Plug 'airblade/vim-gitgutter' + + nmap ]h (GitGutterNextHunk) + nmap [h (GitGutterPrevHunk) + omap ih (GitGutterTextObjectInnerPending) + omap ah (GitGutterTextObjectOuterPending) + xmap ih (GitGutterTextObjectInnerVisual) + xmap ah (GitGutterTextObjectOuterVisual) + + "}}} +" #MatchTagAlways{{{ +" always highlights xml/html tags enclosing cursor + " https://github.com/Valloric/MatchTagAlways + Plug 'Valloric/MatchTagAlways' +let g:mta_filetypes = { + \ 'jinja' : 1, + \ 'html' : 1, + \ 'vue' : 1, + \ 'xhtml' : 1, + \ 'xml' : 1, + \} + "}}} +" #quickscope{{{ +" highlights unique characters when using f, F, etc + " https://github.com/unblevable/quick-scope + Plug 'unblevable/quick-scope' + let g:qs_highlight_on_keys = ['f', 'F', 't', 'T'] + "}}} +" #switch {{{ + "https://github.com/AndrewRadev/switch.vim + Plug 'AndrewRadev/switch.vim' + + let g:switch_mapping = '-' + let g:switch_custom_definitions = [ + \ ['0', '1'], + \ ['ease-in', 'ease-out', 'ease-in-out', 'linear'], + \ ['auto', 'none'], + \ ['left', 'right'], + \ ['top', 'bottom'], + \ ['row', 'column'], + \ ['relative', 'absolute', 'fixed'], + \ ['private', 'public', 'protected'] + \ ] + + "}}} +" #ultisnips {{{ + " https://github.com/sirver/UltiSnips + Plug 'SirVer/ultisnips' + " and some snippets + " https://github.com/honza/vim-snippets + " Plug 'honza/vim-snippets' + + nnoremap ul :call ListUltisnips() + inoremap jkul :call ListUltisnips() + + let g:UltiSnipsSnippetsDir='~/.vim/UltiSnips' + " Trigger configuration. Do not use if you use https://github.com/Valloric/YouCompleteMe. + let g:UltiSnipsExpandTrigger='' + let g:UltiSnipsJumpForwardTrigger='' + let g:UltiSnipsJumpBackwardTrigger='' + let g:UltiSnipsEditSplit='horizontal' + + function! ListUltisnips() abort"{{{ + let l:snips = UltiSnips#SnippetsInCurrentScope(1) + let l:keylist = sort(keys(l:snips)) + echo ' --------------------------------------------------' + for l:key in l:keylist + echo printf(" %-10s\t%s", l:key, l:snips[l:key]) + endfor + echo '---------------------------------------------------' + endfunction + + "}}} + function! CompleteSnippets(findstart, base)"{{{ + if a:findstart + let l:line = getline('.') + let l:start = col('.') - 1 + while l:start > 0 && l:line[l:start - 1] =~ '\a' + let l:start -= 1 + endwhile + return l:start + else + let l:res = [] + let l:snips = UltiSnips#SnippetsInCurrentScope(1) + let l:keylist = sort(keys(l:snips)) + for l:key in l:keylist + if l:key =~ '^' . a:base + let l:item = {'word': l:key, 'menu': l:snips[l:key]} + call add(l:res, l:item) + endif + endfor + return l:res + endif + endfunction + + "}}} + + set completefunc=CompleteSnippets + + "}}} +" #Netrw {{{ + + let g:netrw_liststyle=3 +" let g:netrw_list_hide=netrw_gitignore#Hide() + let g:netrw_preview = 0 + let g:netrw_winsize = 50 + let g:netrw_altv = &spr + let g:netrw_alto = 0 + let g:netrw_altfile = 1 + let g:netrw_mousemaps = 0 + let g:netrw_keepdir = 0 + + "}}} +" #Obsession{{{ + " fork of tpope/vim-obsession + Plug 'studio-vx/vim-obsession' + + "}}} +" #tcomment_vim{{{ + " https://github.com/tomtom/tcomment_vim + Plug 'tomtom/tcomment_vim' + +"}}} +" #vim-rsi{{{ + "https://github.com/tpope/vim-rsi + Plug 'tpope/vim-rsi' + + "}}} +" #vim-repeat{{{ + " https://github.com/tpope/vim-repeat + " makes repeat . work for more stuff + Plug 'tpope/vim-repeat' + + "}}} +" #vim-surround{{{ + Plug 'tpope/vim-surround' + + "}}} + +" #vim-wakatime{{{ + Plug 'wakatime/vim-wakatime' + + "}}} + +" reconfigure and learn to use properly +" #vim-fzf {{{ +" https://github.com/junegunn/fzf.vim +Plug 'junegunn/fzf' +Plug 'junegunn/fzf.vim' + +nnoremap fg :GFiles +nnoremap ff :Files +nnoremap fh :History +nnoremap fb :Buffers +nnoremap fH :Helptags + +let g:fzf_preview_window = 'right:60%' +let g:fzf_colors = + \ { 'fg': ['fg', 'Normal'], + \ 'bg': ['bg', 'Normal'], + \ 'hl': ['fg', 'Label'], + \ 'fg+': ['fg', 'CursorLine', 'CursorColumn', 'Normal'], + \ 'bg+': ['bg', 'CursorLine', 'CursorColumn'], + \ 'hl+': ['fg', 'WildMenu'], + \ 'info': ['fg', 'Comment'], + \ 'border': ['fg', 'Comment'], + \ 'prompt': ['fg', 'Constant'], + \ 'pointer': ['fg', 'Special'], + \ 'marker': ['fg', 'Keyword'], + \ 'spinner': ['fg', 'Label'], + \ 'header': ['fg', 'Comment'] } + +" Rg that doesn't ignore .gitignore or any other files +command! -bang -nargs=* Rgall + \ call fzf#vim#grep( + \ 'rg -uuu --column --line-number --no-heading --color=always --smart-case -- '.shellescape(), 1, + \ fzf#vim#with_preview(), 0) + +"}}} +" #vim-shellcheck{{{ +" https://github.com/itspriddle/vim-shellcheck + Plug 'itspriddle/vim-shellcheck' + + "}}} +" #vim-markdown{{{ +" https://github.com/plasticboy/vim-markdown +Plug 'plasticboy/vim-markdown' +let g:vim_markdown_toc_autofit = 1 +let g:vim_markdown_fenced_languages = ['bash=sh'] +"}}} +" #undotree {{{ + Plug 'mbbill/undotree' + nnoremap ut :UndotreeToggle + + "}}} + +" #vim-floaterm{{{ +" https://github.com/voldikss/floaterm +" allows to open floating terminal + Plug 'voldikss/vim-floaterm' + let g:floaterm_opener = 'edit' + " nnoremap lf :FloatermNew --height=0.9 --width=0.9 lf + nnoremap lg :FloatermNew --height=0.9 --width=0.9 lazygit + "}}} +" #vim-Jinja2-Syntax{{{ +" https://github.com/studio-vx/Vim-Jinja2-Syntax +" original: https://github.com/Glench/Vim-Jinja2-Syntax + Plug 'studio-vx/Vim-Jinja2-Syntax' + + "}}} + +" ------------------------------------------------------------------------------ + +call plug#end() +runtime macros/matchit.vim + +" require lua init modules +lua < 1 + let l:customtabline .= '%' . l:tabnumber . 'T' + let l:customtabline .= (l:tabnumber == l:currenttabnum ? '%1*' : '%2*') + + let l:customtabline .= (l:tabnumber == l:currenttabnum ? '%#TabLineNumSel#' : '%#TabLineNum#') + let l:customtabline .= ' ' . l:tabnumber . ' ' + let l:customtabline .= (l:tabnumber == l:currenttabnum ? '%#TabLineItemSel#' : '%#TabLineItem#') + endif + + let l:bufnr = l:buflist[l:winnr - 1] + let l:file = bufname(l:bufnr) + let l:buftype = getbufvar(l:bufnr, '&buftype') + + if l:buftype ==# 'help' + let l:file = 'help:' . fnamemodify(l:file, ':t:r') + + elseif l:buftype ==# 'quickfix' + let l:file = 'quickfix' + + elseif l:buftype ==# 'nofile' + if l:file =~# '\/.' + let l:file = substitute(l:file, '.*\/\ze.', '', '') + endif + + else + let l:file = fnamemodify(l:file, ':p:t') + + endif + + if l:file ==# '' + let l:file = "''" + endif + + let l:customtabline .= l:file . '%T%#TabLineFill# ' + + let l:tabnumber = l:tabnumber + 1 + + endwhile + + let l:customtabline .= '%T%#TabLineFill#%=' + + let l:customtabline .= '%#TabLineItem# %{getcwd()}% ' + if exists('*ObsessionStatus') + let l:customtabline .= "%#TabLineItem# %{ObsessionStatus(fnamemodify(v:this_session,':t'),'---')} %*" + endif + + return l:customtabline + +endfunction +"}}} + +set tabline=%!MyTabLine() +set showtabline=2 + + +" vim: set foldmethod=marker: diff --git a/init.vim b/init.vim new file mode 100644 index 0000000..b972846 --- /dev/null +++ b/init.vim @@ -0,0 +1,6 @@ +if exists('g:vscode') + " VSCode extension + source ~/.config/nvim/init.vscode.vim +else + source ~/.config/nvim/init.full.vim +endif diff --git a/init.vscode.vim b/init.vscode.vim new file mode 100644 index 0000000..1b359a9 --- /dev/null +++ b/init.vscode.vim @@ -0,0 +1,11 @@ +set undofile +set undodir=~/.config/nvim/undodir +set backupdir=~/.nvim/tmpdir +set directory=~/.nvim/tmpdir + +set ignorecase +set smartcase + +set iskeyword+=- + +set scrolloff=4 diff --git a/lazy-lock.json b/lazy-lock.json deleted file mode 100644 index aa016cd..0000000 --- a/lazy-lock.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "Comment.nvim": { "branch": "master", "commit": "e30b7f2008e52442154b66f7c519bfd2f1e32acb" }, - "conform.nvim": { "branch": "master", "commit": "016802de402556da54c36bd7359b441266b01cdd" }, - "copilot.lua": { "branch": "master", "commit": "82607bbb8528222a9a28bfcab0aceb3a7fed7e85" }, - "gitsigns.nvim": { "branch": "main", "commit": "d4854fa9a94b5c8b37dd209fb4a19e98e764186f" }, - "indent-blankline.nvim": { "branch": "master", "commit": "f1e186e44d3b7f9ae918008e2c28ce37c6023d2d" }, - "lazy.nvim": { "branch": "main", "commit": "306a05526ada86a7b30af95c5cc81ffba93fef97" }, - "mason-lspconfig.nvim": { "branch": "main", "commit": "a338f44149f5673882c32629697d67b0c0547aec" }, - "mason-tool-installer.nvim": { "branch": "main", "commit": "443f1ef8b5e6bf47045cb2217b6f748a223cf7dc" }, - "mason.nvim": { "branch": "main", "commit": "2a6940af80375532e5e9e7c1f2fc6319a1b7a69d" }, - "nvim-autopairs": { "branch": "master", "commit": "3172f40c16563db871a58f20d205c710ad782311" }, - "nvim-lint": { "branch": "master", "commit": "f6230a5c06ba59e6059c14637f1dbe29a7978b9b" }, - "nvim-lspconfig": { "branch": "master", "commit": "3bccb6fa49a3a75bfb6d92fed63b13a71a85cfaf" }, - "nvim-surround": { "branch": "main", "commit": "2e93e154de9ff326def6480a4358bfc149d5da2c" }, - "nvim-treesitter": { "branch": "main", "commit": "a2f694478be07f89c2d03cc17858a8745a400c4b" }, - "nvim-treesitter-textobjects": { "branch": "main", "commit": "5c7b0263797dfd1bd6202f2b219f3b53a80b2187" }, - "nvim-ts-autotag": { "branch": "main", "commit": "d7220b55e16ed3c04e88086256def5d282429493" }, - "nvim-ufo": { "branch": "main", "commit": "ab3eb124062422d276fae49e0dd63b3ad1062cfc" }, - "plenary.nvim": { "branch": "master", "commit": "74b06c6c75e4eeb3108ec01852001636d85a932b" }, - "promise-async": { "branch": "main", "commit": "119e8961014c9bfaf1487bf3c2a393d254f337e2" }, - "telescope-fzf-native.nvim": { "branch": "main", "commit": "b25b749b9db64d375d782094e2b9dce53ad53a40" }, - "telescope.nvim": { "branch": "0.1.x", "commit": "a0bbec21143c7bc5f8bb02e0005fa0b982edc026" } -} diff --git a/lua/abbreviations.lua b/lua/abbreviations.lua deleted file mode 100644 index f92aabb..0000000 --- a/lua/abbreviations.lua +++ /dev/null @@ -1,10 +0,0 @@ --- Abbreviations (common typo corrections) --- Insert-mode abbreviations for frequent typos - -vim.cmd.iabbrev('adn', 'and') -vim.cmd.iabbrev('waht', 'what') -vim.cmd.iabbrev('tehn', 'then') -vim.cmd.iabbrev('functin', 'function') -vim.cmd.iabbrev('positin', 'position') - -return {} diff --git a/lua/autocmds.lua b/lua/autocmds.lua deleted file mode 100644 index 3ab254b..0000000 --- a/lua/autocmds.lua +++ /dev/null @@ -1,279 +0,0 @@ --- Non-plugin autocommands (minimal placeholder for bootstrap) -local aug = vim.api.nvim_create_augroup("UserDefaults", { clear = true }) - --- Templates (auto-populate new files from templates) -local template_aug = vim.api.nvim_create_augroup("Templates", { clear = true }) - -vim.api.nvim_create_autocmd("BufNewFile", { - group = template_aug, - pattern = "*.sh", - callback = function() - -- Read template at top of file, then move to end - vim.cmd("0read ~/.config/nvim/templates/template.sh") - vim.cmd("normal! G") - end, -}) - --- Per-filetype indentation settings to match formatters - --- PHP: WordPress coding standards (tabs, displayed as 2 spaces) -vim.api.nvim_create_autocmd("FileType", { - group = aug, - pattern = "php", - callback = function() - vim.opt_local.expandtab = false -- Use actual tabs (WordPress standard) - vim.opt_local.tabstop = 2 -- Display tabs as 2 spaces wide - vim.opt_local.shiftwidth = 2 -- Indent/outdent by 2 columns (one tab) - vim.opt_local.softtabstop = 2 -- Tab key inserts 2 columns (one tab) - end, -}) - --- JavaScript, TypeScript, JSON, CSS: Prettier defaults (2 spaces) -vim.api.nvim_create_autocmd("FileType", { - group = aug, - pattern = { "javascript", "javascriptreact", "typescript", "typescriptreact", "json", "css", "scss", "html" }, - callback = function() - vim.opt_local.expandtab = true -- Use spaces (Prettier default) - vim.opt_local.tabstop = 2 -- Display as 2 spaces - vim.opt_local.shiftwidth = 2 -- Indent by 2 - vim.opt_local.softtabstop = 2 - end, -}) - --- Lua: stylua defaults (2 spaces) -vim.api.nvim_create_autocmd("FileType", { - group = aug, - pattern = "lua", - callback = function() - vim.opt_local.expandtab = true -- Use spaces (common for Lua configs) - vim.opt_local.tabstop = 2 -- Display as 2 spaces - vim.opt_local.shiftwidth = 2 -- Indent by 2 - vim.opt_local.softtabstop = 2 - end, -}) - --- Markdown: Prettier defaults (2 spaces) + spellcheck -vim.api.nvim_create_autocmd("FileType", { - group = aug, - pattern = "markdown", - callback = function() - vim.opt_local.expandtab = true -- Use spaces - vim.opt_local.tabstop = 2 -- Display as 2 spaces - vim.opt_local.shiftwidth = 2 -- Indent by 2 - vim.opt_local.softtabstop = 2 - vim.opt_local.spell = true -- Enable spellcheck for markdown - end, -}) - --- Python: Black defaults (4 spaces) -vim.api.nvim_create_autocmd("FileType", { - group = aug, - pattern = "python", - callback = function() - vim.opt_local.expandtab = true -- Use spaces (PEP 8) - vim.opt_local.tabstop = 4 -- Display as 4 spaces - vim.opt_local.shiftwidth = 4 -- Indent by 4 - vim.opt_local.softtabstop = 4 - end, -}) - --- Colorize diagnostic severity in quickfix/location list -vim.api.nvim_create_autocmd("FileType", { - group = aug, - pattern = "qf", -- Applies to both quickfix and location list - callback = function() - -- Disable spell checking in quickfix/location list windows - vim.opt_local.spell = false - - -- Use matchadd() for higher priority highlighting - -- This will override the default qf syntax - vim.fn.matchadd("qfError", "\\", 10) - vim.fn.matchadd("qfWarning", "\\", 10) - vim.fn.matchadd("qfInfo", "\\", 10) - vim.fn.matchadd("qfHint", "\\", 10) - vim.fn.matchadd("qfNote", "\\", 10) - - -- Also match uppercase variants - vim.fn.matchadd("qfError", "\\", 10) - vim.fn.matchadd("qfWarning", "\\", 10) - vim.fn.matchadd("qfInfo", "\\", 10) - vim.fn.matchadd("qfHint", "\\", 10) - vim.fn.matchadd("qfNote", "\\", 10) - end, -}) - --- Session management: auto-load on startup, auto-save on exit (only if Session.vim exists) -local session_aug = vim.api.nvim_create_augroup("SessionManagement", { clear = true }) -local sanitize_session_files - --- Auto-load Session.vim if it exists in the current directory -vim.api.nvim_create_autocmd("VimEnter", { - group = session_aug, - pattern = "*", - once = true, - callback = function() - -- Only auto-load if: - -- 1. Session.vim exists in cwd - -- 2. No files were specified on command line (vim.fn.argc() == 0) - -- 3. Not started with nvim -S (check if we already loaded a session) - if vim.fn.argc() == 0 and vim.fn.filereadable("Session.vim") == 1 and vim.v.this_session == "" then - vim.cmd("silent! source Session.vim") - end - end, -}) - --- Ensure filetype is detected for current buffer after session load -vim.api.nvim_create_autocmd("SessionLoadPost", { - group = session_aug, - pattern = "*", - callback = function() - sanitize_session_files() - - -- Trigger BufReadPost for all loaded buffers to ensure Treesitter/LSP attach - vim.schedule(function() - for _, buf in ipairs(vim.api.nvim_list_bufs()) do - if vim.api.nvim_buf_is_loaded(buf) and vim.bo[buf].buftype == "" then - vim.api.nvim_exec_autocmds("BufReadPost", { buffer = buf }) - end - end - end) - end, -}) - -local function is_netrw_session_buffer(buf) - return vim.api.nvim_buf_is_valid(buf) - and (vim.bo[buf].filetype == "netrw" or vim.api.nvim_buf_get_name(buf):match("NetrwTreeListing$") ~= nil) -end - -local function session_fallback_buffer(excluded) - excluded = excluded or {} - for _, buf in ipairs(vim.api.nvim_list_bufs()) do - local name = vim.api.nvim_buf_get_name(buf) - if - vim.api.nvim_buf_is_valid(buf) - and not excluded[buf] - and vim.bo[buf].buflisted - and vim.bo[buf].buftype == "" - and name ~= "" - and vim.uv.fs_stat(name) ~= nil - and not is_netrw_session_buffer(buf) - then - return buf - end - end - - return vim.api.nvim_create_buf(true, false) -end - -local function is_local_file_path(path) - return path ~= "" and path:match("^%a[%w+.-]*://") == nil -end - -sanitize_session_files = function() - local missing = {} - for _, buf in ipairs(vim.api.nvim_list_bufs()) do - if vim.api.nvim_buf_is_valid(buf) and vim.bo[buf].buftype == "" then - local name = vim.api.nvim_buf_get_name(buf) - if is_local_file_path(name) and vim.uv.fs_stat(name) == nil and not vim.bo[buf].modified then - missing[buf] = true - end - end - end - - if next(missing) then - local fallback - for _, win in ipairs(vim.api.nvim_list_wins()) do - local buf = vim.api.nvim_win_get_buf(win) - if missing[buf] then - fallback = fallback or session_fallback_buffer(missing) - vim.api.nvim_win_set_buf(win, fallback) - end - end - - for buf in pairs(missing) do - if vim.api.nvim_buf_is_valid(buf) then - pcall(vim.api.nvim_buf_delete, buf, { force = true }) - end - end - end - - local args = vim.fn.argv() - local existing = {} - for _, arg in ipairs(args) do - local path = is_local_file_path(arg) and vim.fn.fnamemodify(arg, ":p") or nil - if not path or vim.uv.fs_stat(path) ~= nil then - table.insert(existing, arg) - end - end - - if #existing ~= #args then - vim.cmd("%argdelete") - for _, arg in ipairs(existing) do - vim.cmd.argadd({ args = { arg } }) - end - end -end - -local function close_session_tab(tab) - if vim.api.nvim_tabpage_close then - pcall(vim.api.nvim_tabpage_close, tab, true) - return - end - - pcall(function() - vim.api.nvim_set_current_tabpage(tab) - vim.cmd("tabclose!") - end) -end - -local function omit_netrw_from_session() - local tabs_with_netrw = {} - for _, tab in ipairs(vim.api.nvim_list_tabpages()) do - for _, win in ipairs(vim.api.nvim_tabpage_list_wins(tab)) do - if is_netrw_session_buffer(vim.api.nvim_win_get_buf(win)) then - tabs_with_netrw[tab] = true - break - end - end - end - - for tab in pairs(tabs_with_netrw) do - if vim.api.nvim_tabpage_is_valid(tab) then - for _, win in ipairs(vim.api.nvim_tabpage_list_wins(tab)) do - if vim.api.nvim_win_is_valid(win) and vim.wo[win].previewwindow then - pcall(vim.api.nvim_win_close, win, true) - end - end - - if vim.api.nvim_tabpage_is_valid(tab) then - for _, win in ipairs(vim.api.nvim_tabpage_list_wins(tab)) do - if vim.api.nvim_win_is_valid(win) and is_netrw_session_buffer(vim.api.nvim_win_get_buf(win)) then - if #vim.api.nvim_tabpage_list_wins(tab) > 1 then - pcall(vim.api.nvim_win_close, win, true) - elseif #vim.api.nvim_list_tabpages() > 1 then - close_session_tab(tab) - else - vim.api.nvim_win_set_buf(win, session_fallback_buffer()) - end - end - end - end - end - end -end - --- Auto-save session on exit, but ONLY if Session.vim already exists -vim.api.nvim_create_autocmd("VimLeavePre", { - group = session_aug, - pattern = "*", - callback = function() - -- Only save if Session.vim exists (user manually created it) - if vim.fn.filereadable("Session.vim") == 1 then - omit_netrw_from_session() - sanitize_session_files() - vim.cmd("mksession! Session.vim") - end - end, -}) - -return {} diff --git a/lua/completion.lua b/lua/completion.lua deleted file mode 100644 index ea208d5..0000000 --- a/lua/completion.lua +++ /dev/null @@ -1,21 +0,0 @@ --- Neovim 0.12 native insert-mode completion. -if vim.fn.has("nvim-0.12") == 0 then - return -end - -vim.opt.autocomplete = true -vim.opt.autocompletedelay = 150 -vim.opt.completeopt = { "menu", "menuone", "noselect", "popup", "fuzzy" } -vim.opt.complete = { ".^10", "w^5", "b^5", "u^5" } - -vim.api.nvim_create_autocmd("FileType", { - pattern = "TelescopePrompt", - callback = function(args) - vim.bo[args.buf].autocomplete = false - end, - desc = "Disable native completion in Telescope prompts", -}) - -vim.keymap.set("i", "", function() - vim.lsp.completion.get() -end, { desc = "Completion: Trigger LSP suggestions", silent = true }) diff --git a/lua/init-cmp.lua b/lua/init-cmp.lua new file mode 100644 index 0000000..6e42a8e --- /dev/null +++ b/lua/init-cmp.lua @@ -0,0 +1,49 @@ +local cmp = require 'cmp' + +cmp.setup({ + window = {documentation = cmp.config.window.bordered({border = "single"})}, + formatting = { + format = function(entry, vim_item) + -- set a name for each source + vim_item.menu = ({ + nvim_lsp = "[LSP]", + path = "[Path]", + buffer = "[Buffer]", + ultisnips = "[UltiSnips]" + })[entry.source.name] + return vim_item + end + }, + completion = { + keyword_length = 1, + max_item_count = 20 + -- autocomplete = false + }, + snippet = {expand = function(args) vim.fn["UltiSnips#Anon"](args.body) end}, + mapping = { + [''] = cmp.mapping.scroll_docs(-4), + [''] = cmp.mapping.scroll_docs(4), + [""] = cmp.mapping({ + i = function() + if cmp.visible() then + cmp.select_next_item({behavior = cmp.SelectBehavior.Insert}) + else + cmp.complete() + end + end + }) + }, + sources = { + {name = 'nvim_lsp', max_item_count = 8, keyword_length = 3}, + {name = 'path'}, + {name = 'buffer', + option = { + keyword_length = 4, + max_item_count = 20, + get_bufnrs = function() + return vim.api.nvim_list_bufs() + end + }}, + {name = 'ultisnips', priority_weight = 10, keyword_length = 1} + } +}) diff --git a/lua/init-indent-blankline.lua b/lua/init-indent-blankline.lua new file mode 100644 index 0000000..8a8fae6 --- /dev/null +++ b/lua/init-indent-blankline.lua @@ -0,0 +1,5 @@ + +require("indent_blankline").setup { + space_char_blankline = " ", + show_current_context = true, +} diff --git a/lua/init-lsp.lua b/lua/init-lsp.lua new file mode 100644 index 0000000..cee92ef --- /dev/null +++ b/lua/init-lsp.lua @@ -0,0 +1,230 @@ +vim.cmd [[ + sign define LspDiagnosticsSignError text= texthl= linehl= numhl=LspDiagnosticsLineNrError + sign define LspDiagnosticsSignWarning text= texthl= linehl= numhl=LspDiagnosticsLineNrWarning + sign define LspDiagnosticsSignInfo text= texthl= linehl= numhl=LspDiagnosticsLineNrInformation + sign define LspDiagnosticsSignHint text= texthl= linehl= numhl=LspDiagnosticsLineNrHint +]] +-- +-- lspconfig +local nvim_lsp = require('lspconfig') + +-- Use a loop to conveniently call 'setup' on multiple servers and +-- map buffer local keybindings when the language server attaches +local servers = { + -- astro + -- npm install -g @astrojs/language-server + 'astro', -- npm i -g bash-language-server + -- no formatting support + 'bashls', -- npm i -g vscode-langservers-extracted + -- no formatting support + 'cssls', -- npm install -g intelephense + -- suports formatting + 'intelephense', + + -- https://phpactor.readthedocs.io/en/master/usage/standalone.html + 'phpactor', -- npm install -g pyright + -- static type checker + 'pyright', -- https://github.com/neovim/nvim-lspconfig/wiki + -- 'tailwindcss', + -- npm install -g typescript typescript-language-server + -- supports formatting + 'tsserver', -- npm install -g vim-language-server + -- no formatting support + 'vimls', -- vue + -- use vetur + 'yamlls' -- no formatting support + -- is now automatically started/configured by rust-tools + -- sudo pacman -Syu rust-analyzer + -- 'rust_analyzer' +} + +-- Use an on_attach function to only map the following keys +-- after the language server attaches to the current buffer +local on_attach = function(client, bufnr) + local function buf_set_keymap(...) + vim.api.nvim_buf_set_keymap(bufnr, ...) + end + + local function buf_set_option(...) + vim.api.nvim_buf_set_option(bufnr, ...) + end + + -- Enable completion triggered by + buf_set_option('omnifunc', 'v:lua.vim.lsp.omnifunc') + -- Mappings. + local opts = {noremap = true, silent = true} + -- See `:help vim.lsp.*` for documentation on any of the below functions + buf_set_keymap('n', '[d', + 'lua vim.diagnostic.goto_prev({float = {...}})', + opts) + buf_set_keymap('n', ']d', + 'lua vim.diagnostic.goto_next({float = {...}})', + opts) + buf_set_keymap('n', 'gd', 'lua vim.lsp.buf.definition()', opts) + buf_set_keymap('n', 'gD', 'lua vim.lsp.buf.declaration()', opts) + buf_set_keymap('n', 'gi', 'lua vim.lsp.buf.implementation()', opts) + buf_set_keymap('n', 'gr', 'lua vim.lsp.buf.references()', opts) + buf_set_keymap('n', 'gl', + 'lua vim.diagnostic.open_float(buffer, {{opts}, scope="line"})', + opts) + buf_set_keymap('n', 'gh', 'lua vim.lsp.buf.hover()', opts) + buf_set_keymap('n', '', 'lua vim.lsp.buf.signature_help()', + opts) + buf_set_keymap('n', 'T', + 'lua vim.lsp.buf.type_definition()', opts) + buf_set_keymap('n', 'l', 'lua vim.diagnostic.setloclist()', + opts) + buf_set_keymap('n', 'q', 'lua vim.diagnostic.setqflist()', + opts) + buf_set_keymap('n', 'ca', 'lua vim.lsp.buf.code_action()', + opts) + buf_set_keymap('n', 'rn', 'lua vim.lsp.buf.rename()', opts) + buf_set_keymap('n', 'f', 'lua vim.lsp.buf.formatting()', + opts) + -- buf_set_keymap('n', 'wa', 'lua vim.lsp.buf.add_workspace_folder()', opts) + -- buf_set_keymap('n', 'wr', 'lua vim.lsp.buf.remove_workspace_folder()', opts) + -- buf_set_keymap('n', 'wl', 'lua print(vim.inspect(vim.lsp.buf.list_workspace_folders()))', opts) + + if client.name == 'phpactor' then + client.server_capabilities.find_references = false; + end + + if client.name == 'tsserver' or client.name == 'intelephense' then + client.server_capabilities.document_formatting = false; + -- print(vim.inspect(client.server_capabilities)); + end + + if client.server_capabilities.document_formatting then + vim.cmd [[augroup lsp_formatting]] + vim.cmd [[autocmd!]] + vim.cmd [[autocmd BufWritePre :lua vim.lsp.buf.formatting_seq_sync({}, 3000)]] + vim.cmd [[augroup END]] + end + + if client.server_capabilities.document_highlight then + vim.cmd [[ + augroup lsp_document_highlight + autocmd! * + autocmd CursorHold lua vim.lsp.buf.document_highlight() + autocmd CursorMoved lua vim.lsp.buf.clear_references() + augroup END + ]] + end +end + +local capabilities = vim.lsp.protocol.make_client_capabilities() +capabilities = require('cmp_nvim_lsp').update_capabilities(capabilities) +capabilities.textDocument.completion.completionItem.snippetSupport = true + +for _, lsp in ipairs(servers) do + nvim_lsp[lsp].setup { + on_attach = on_attach, + capabilities = capabilities, + flags = {debounce_text_changes = 150} + } +end + +local runtime_path = vim.split(package.path, ';') +table.insert(runtime_path, "lua/?.lua") +table.insert(runtime_path, "lua/?/init.lua") + +require'lspconfig'.sumneko_lua.setup { + settings = { + Lua = { + runtime = { + -- Tell the language server which version of Lua you're using (most likely LuaJIT in the case of Neovim) + version = 'LuaJIT', + -- Setup your lua path + path = runtime_path + }, + diagnostics = { + -- Get the language server to recognize the `vim` global + globals = {'vim'} + }, + workspace = { + -- Make the server aware of Neovim runtime files + library = vim.api.nvim_get_runtime_file("", true) + }, + -- Do not send telemetry data containing a randomized but unique identifier + telemetry = {enable = false} + } + } +} + +-- toml +-- 'taplo' +-- -- sudo pacman -Syu taplo-cli +require'lspconfig'.taplo.setup { + on_attach = on_attach, + capabilities = capabilities, + flags = {debounce_text_changes = 150}, + cmd = {"taplo", "lsp", "stdio"} +} + +-- rust-tools +require('rust-tools').setup({ + server = { + on_attach = on_attach, + capabilities = capabilities, + flags = {debounce_text_changes = 150}, + + settings = {["rust-analyzer"] = {checkOnSave = {command = "clippy"}}} + } +}) +-- inlay hints +require('rust-tools').inlay_hints.enable() +------ + +-- null-ls +local null_ls = require("null-ls") + +local null_ls_utils = require("null-ls.utils") +local root = null_ls_utils.get_root() +local eslint_command = root .. "/node_modules/eslint/bin/eslint.js" +-- print(eslint_command); + +local sources = { + null_ls.builtins.formatting.prettierd, + null_ls.builtins.diagnostics.eslint.with({ + condition = function(utils) + local has_file = utils.root_has_file({ + "node_modules/@wordpress/scripts/config/.eslintrc.js" + }) + -- print("condition") + -- print(has_file) + return has_file + end, + extra_args = { + "--no-eslintrc", "--config ", + root .. "/node_modules/@wordpress/scripts/config/.eslintrc.js", + "--ignore-path ", + root .. "/node_modules/@wordpress/scripts/config/.eslintignore" + } + }), -- + -- null_ls.builtins.diagnostics.eslint.with({ + -- filetypes = { "javascript", "javascriptreact", "typescript", "typescriptreact", "vue", "svelte", "astro" }, + -- command = eslint_command + -- }), + -- null_ls.builtins.diagnostics.eslint.with({ + -- condition = function(utils) + -- local has_file1 = utils.root_has_file({".eslintrc.js"}) + -- local has_file2 = utils.root_has_file({"gatsby-config.js"}) + -- print("condition") + -- print(has_file1) + -- print(has_file2) + -- return has_file1 and has_file2 + -- end + -- }), -- + null_ls.builtins.diagnostics.phpcs.with({ + condition = function(utils) + return not utils.root_has_file({"vendor/bin/phpcs"}) + end, + args = {"--standard=PSR12", "--report=json", "-s", "-"} + }), -- + null_ls.builtins.formatting.black, -- black + null_ls.builtins.diagnostics.shellcheck, -- shellcheck, + null_ls.builtins.diagnostics.flake8, -- flake8 + null_ls.builtins.formatting.lua_format -- luaFormatter +} + +null_ls.setup({sources = sources, on_attach = on_attach}) diff --git a/lua/init-plugins.lua b/lua/init-plugins.lua new file mode 100644 index 0000000..5cd9fba --- /dev/null +++ b/lua/init-plugins.lua @@ -0,0 +1,35 @@ +-- nvim-autopairs +require('nvim-autopairs').setup {} +------ + +-- cmp +require("cmp").setup({ + map_cr = false, -- map on insert mode + map_complete = false, -- it will auto insert `(` after select function or method item + auto_select = true -- automatically select the first item +}) +------ + +-- nvim-ts-autotag +require'nvim-treesitter.configs'.setup { + autotag = { + enable = true, + filetypes = { + -- not working for astro files + 'html', 'javascript', 'typescript', 'javascriptreact', 'typescriptreact', 'svelte', 'vue', 'tsx', 'jsx', 'rescript', 'astro', + 'xml', + 'php', + 'markdown', + 'glimmer','handlebars','hbs' + }, + } +} +------ + +-- nvim-ufo +require('ufo').setup({ + provider_selector = function(bufnr, filetype, buftype) + return {'treesitter', 'indent'} + end +}) +------ diff --git a/lua/init-treesitter.lua b/lua/init-treesitter.lua new file mode 100644 index 0000000..f2574e4 --- /dev/null +++ b/lua/init-treesitter.lua @@ -0,0 +1,14 @@ +require'nvim-treesitter.configs'.setup { + -- ensure_installed = "maintained", -- one of "all", "maintained" (parsers with maintainers), or a list of languages + ignore_install = {"c"}, -- List of parsers to ignore installing + highlight = { + enable = true, -- false will disable the whole extension + disable = {"c", "rust"}, -- list of language that will be disabled + -- Setting this to true will run `:h syntax` and tree-sitter at the same time. + -- Set this to `true` if you depend on 'syntax' being enabled (like for indentation). + -- Using this option may slow down your editor, and you may see some duplicate highlights. + -- Instead of true it can also be a list of languages + additional_vim_regex_highlighting = false + }, + indent = {enable = true} +} diff --git a/lua/init.lua b/lua/init.lua new file mode 100644 index 0000000..474893d --- /dev/null +++ b/lua/init.lua @@ -0,0 +1,38 @@ +vim.o.foldmethod = 'expr' +vim.o.foldexpr = 'nvim_treesitter#foldexpr()' + +vim.diagnostic.config({ + virtual_text = false, + signs = true, + underline = false, + update_in_insert = false, + severity_sort = true, + float = { + border = "single", + source = "always" -- Or "if_many" + } +}) + +local signs = {Error = "● ", Warn = "● ", Hint = "● ", Info = "● "} +for type, icon in pairs(signs) do + local hl = "DiagnosticSign" .. type + vim.fn.sign_define(hl, {text = icon, texthl = hl, numhl = hl}) +end + +local border = { + {"┌", "FloatBorder"}, {"─", "FloatBorder"}, {"┐", "FloatBorder"}, + {"│", "FloatBorder"}, {"┘", "FloatBorder"}, {"─", "FloatBorder"}, + {"└", "FloatBorder"}, {"│", "FloatBorder"} +} + +vim.lsp.handlers["textDocument/hover"] = + vim.lsp.with(vim.lsp.handlers.hover, {border = "single"}) +vim.lsp.handlers["textDocument/signatureHelp"] = + vim.lsp.with(vim.lsp.handlers.signature_help, {border = "single"}) + +local orig_util_open_floating_preview = vim.lsp.util.open_floating_preview +function vim.lsp.util.open_floating_preview(contents, syntax, opts, ...) + opts = opts or {} + opts.border = opts.border or border + return orig_util_open_floating_preview(contents, syntax, opts, ...) +end diff --git a/lua/keymaps.lua b/lua/keymaps.lua deleted file mode 100644 index beba015..0000000 --- a/lua/keymaps.lua +++ /dev/null @@ -1,92 +0,0 @@ --- Non-plugin and global helper keymaps --- --- NOTE: LSP keymaps are primarily handled in lua/plugins/lsp.lua via LspAttach. --- Buffer-local keymaps set there take precedence over these global fallbacks. --- --- These global keymaps provide fallback behavior for buffers without LSP attached, --- ensuring that common navigation keys still work with built-in Vim functionality --- (e.g., ctags, included files, man pages). - -local map = vim.keymap.set - --- Neovim 0.12's optional native undo-tree viewer. -if vim.fn.has('nvim-0.12') == 1 then - map('n', 'u', 'Undotree', { desc = 'Undotree: Toggle native undo tree', silent = true }) -end - --- Fallback navigation keymaps for non-LSP buffers --- When LSP attaches, buffer-local keymaps in lsp.lua override these -map('n', 'gd', function() - -- Built-in: jump to definition via tags or included files - vim.cmd("normal! gd") -end, { desc = 'Vim: Go to definition (built-in fallback)', silent = true }) - -map('n', 'gD', function() - -- Built-in: jump to declaration (global) - vim.cmd("normal! gD") -end, { desc = 'Vim: Go to declaration (built-in fallback)', silent = true }) - --- LSP-only keymaps (no useful fallback for these in non-LSP contexts) -map('n', 'gr', '', { desc = 'LSP: References (requires LSP)', silent = true }) -map('n', 'gI', '', { desc = 'LSP: Implementation (requires LSP)', silent = true }) - --- K: Hover/Help with sensible fallback -map('n', 'K', function() - -- Built-in K uses 'keywordprg' (defaults to 'man' for shell scripts, etc.) - -- LSP buffers override this with vim.lsp.buf.hover() in lsp.lua - if vim.bo.keywordprg ~= '' then - vim.cmd("normal! K") - end -end, { desc = 'Vim: Hover/Help (keywordprg fallback)', silent = true }) - --- Quickfix and Location list keymaps -map('n', 'co', 'copen', { desc = 'Quickfix: Open', silent = true }) -map('n', 'cc', 'cclose', { desc = 'Quickfix: Close', silent = true }) -map('n', 'lo', 'lopen', { desc = 'Location list: Open', silent = true }) -map('n', 'lc', 'lclose', { desc = 'Location list: Close', silent = true }) - --- Diagnostic keymaps -map('n', 'xx', vim.diagnostic.setloclist, { desc = 'Diagnostics: Buffer diagnostics (location list)', silent = true }) -map('n', 'xX', vim.diagnostic.setqflist, { desc = 'Diagnostics: All diagnostics (quickfix)', silent = true }) -map('n', 'xe', function() - vim.diagnostic.setloclist({ severity = vim.diagnostic.severity.ERROR }) -end, { desc = 'Diagnostics: Buffer errors (location list)', silent = true }) -map('n', 'xE', function() - vim.diagnostic.setqflist({ severity = vim.diagnostic.severity.ERROR }) -end, { desc = 'Diagnostics: All errors (quickfix)', silent = true }) -map('n', '[d', function() - vim.diagnostic.jump({ count = -1, float = false }) -end, { desc = 'Diagnostics: Previous diagnostic', silent = true }) -map('n', ']d', function() - vim.diagnostic.jump({ count = 1, float = false }) -end, { desc = 'Diagnostics: Next diagnostic', silent = true }) -map('n', 'xd', function() - pcall(vim.diagnostic.open_float) -end, { desc = 'Diagnostics: Show diagnostic under cursor', silent = true }) -map('n', 'xt', function() - vim.diagnostic.enable(not vim.diagnostic.is_enabled()) -end, { desc = 'Diagnostics: Toggle display', silent = true }) - --- Git: Modified, deleted, and untracked files to quickfix -map('n', 'gg', function() - local utils = require('utils') - local qf_list = utils.git_changed_files() - if qf_list then - vim.fn.setqflist(qf_list, 'r') - vim.cmd('copen') - end -end, { desc = 'Git: Changed files to quickfix (with status)', silent = true }) - --- Debug: Show highlight group and color under cursor -map('n', 'hi', function() - require('utils').show_highlight_info() -end, { desc = 'Debug: Show highlight group and color under cursor', silent = true }) - --- UI: Toggle background (light/dark) -map('n', 'bg', function() - if vim.o.background == 'dark' then - vim.o.background = 'light' - else - vim.o.background = 'dark' - end -end, { desc = 'UI: Toggle background (light/dark)', silent = true }) diff --git a/lua/keymaps_reference.lua b/lua/keymaps_reference.lua deleted file mode 100644 index 4e87181..0000000 --- a/lua/keymaps_reference.lua +++ /dev/null @@ -1,74 +0,0 @@ -local M = {} - -local reference_filename = "README.md" -local reference_path = vim.fn.stdpath("config") .. "/" .. reference_filename - -local function read_reference() - local lines = {} - local fd = io.open(reference_path, "r") - if not fd then - return { - ("Keymap reference file not found: %s"):format(reference_path), - "Create README.md to document mappings.", - } - end - - for line in fd:lines() do - table.insert(lines, line) - end - fd:close() - - if #lines == 0 then - lines = { "README.md is empty." } - end - - return lines -end - -local function open_float(lines) - local buf = vim.api.nvim_create_buf(false, true) - vim.api.nvim_buf_set_lines(buf, 0, -1, false, lines) - - vim.bo[buf].buftype = "nofile" - vim.bo[buf].bufhidden = "wipe" - vim.bo[buf].filetype = "markdown" - vim.bo[buf].swapfile = false - vim.bo[buf].modifiable = false - - local width = 0 - for _, line in ipairs(lines) do - width = math.max(width, vim.fn.strdisplaywidth(line)) - end - width = math.min(math.max(width + 4, 60), math.floor(vim.o.columns * 0.9)) - - local height = math.min(#lines, math.floor(vim.o.lines * 0.9)) - if height < 10 then - height = math.min(10, vim.o.lines - 2) - end - - local win_opts = { - relative = "editor", - width = width, - height = height, - row = math.floor((vim.o.lines - height) / 2), - col = math.floor((vim.o.columns - width) / 2), - style = "minimal", - border = "rounded", - } - - local win = vim.api.nvim_open_win(buf, true, win_opts) - vim.keymap.set("n", "q", "close", { buffer = buf, silent = true }) - vim.keymap.set("n", "", "close", { buffer = buf, silent = true }) - return win -end - -function M.open_reference() - local lines = read_reference() - open_float(lines) -end - -vim.api.nvim_create_user_command("KeymapsGuide", function() - M.open_reference() -end, { desc = "Show README.md keymap reference in a floating window" }) - -return M diff --git a/lua/netrw-config.lua b/lua/netrw-config.lua deleted file mode 100644 index 3956620..0000000 --- a/lua/netrw-config.lua +++ /dev/null @@ -1,140 +0,0 @@ -local map = vim.keymap.set -local netrw_preview = require('netrw-preview') -local last_file_buf -local previous_file_buf - -local function is_valid_buffer(buf) - return type(buf) == 'number' and buf > 0 and vim.api.nvim_buf_is_valid(buf) -end - -local function is_real_file_buffer(buf) - return is_valid_buffer(buf) - and vim.bo[buf].buflisted - and vim.bo[buf].buftype == '' - and vim.bo[buf].filetype ~= 'netrw' - and vim.api.nvim_buf_get_name(buf) ~= '' -end - -local function is_netrw_buffer(buf) - if not is_valid_buffer(buf) then - return false - end - - return vim.bo[buf].filetype == 'netrw' or vim.api.nvim_buf_get_name(buf):match('NetrwTreeListing$') ~= nil -end - -local function switch_to_buffer(buf) - vim.cmd('buffer ' .. buf) -end - -local function switch_to_native_alternate() - pcall(vim.cmd, 'buffer #') -end - -local function jump_to_alternate_file() - local alternate = vim.fn.bufnr('#') - - if is_real_file_buffer(alternate) then - switch_to_buffer(alternate) - return - end - - if is_netrw_buffer(alternate) and is_real_file_buffer(previous_file_buf) then - switch_to_buffer(previous_file_buf) - return - end - - switch_to_native_alternate() -end - --- Netrw configuration for file browsing --- Native Neovim file explorer (no plugins required) - --- Hide the banner (that annoying help text at the top) -vim.g.netrw_banner = 0 - --- Tree view by default (3 = tree style) --- Options: 0=thin, 1=long, 2=wide, 3=tree -vim.g.netrw_liststyle = 3 - --- Preview in horizontal split (underneath) -vim.g.netrw_preview = 0 - --- Open preview splits below (1=below, 0=above) -vim.g.netrw_alto = 0 - --- Window size for preview splits (percentage for preview window) --- 50% split when pressing 'p' -vim.g.netrw_winsize = 50 - --- Keep working directory unchanged when browsing (1 = don't change directory) --- Setting to 1 prevents netrw from changing vim's working directory -vim.g.netrw_keepdir = 1 - --- Open files in the same window (replace netrw buffer) --- Options: 0=same window, 1=horizontal split, 2=vertical split, 3=new tab, 4=previous window --- Using 0 so Enter opens file in netrw window itself -vim.g.netrw_browse_split = 0 - --- Sort order: name (empty), time (t), size (s), exten (e) -vim.g.netrw_sort_by = 'name' - --- Preserve netrw's normal listing filter; toggle dotfile visibility with 'gh' -vim.g.netrw_list_hide = [[^\.\.\=/\=$]] - --- Use human-readable file sizes -vim.g.netrw_sizestyle = 'H' - --- Netrw file explorer keymaps --- Open netrw in new tab at current file's directory -map('n', 'nt', function() - local current_file_dir = vim.fn.expand('%:p:h') - vim.cmd('tabnew') - vim.cmd('Explore ' .. vim.fn.fnameescape(current_file_dir)) -end, { desc = 'Netrw: Tab at current file dir', silent = true }) - --- Open netrw in new tab at project root (stored at startup) -map('n', 'nT', function() - vim.cmd('tabnew') - vim.cmd('Explore ' .. vim.fn.fnameescape(vim.g.project_root)) -end, { desc = 'Netrw: Tab at project root', silent = true }) - --- Open netrw in current window at project root (stored at startup) -map('n', 'nr', function() - vim.cmd('Explore ' .. vim.fn.fnameescape(vim.g.project_root)) -end, { desc = 'Netrw: Open at project root', silent = true }) - -map('n', '', jump_to_alternate_file, { desc = 'Buffer: Alternate file skipping netrw', silent = true }) -map('n', '', jump_to_alternate_file, { desc = 'Buffer: Alternate file skipping netrw', silent = true }) - -vim.api.nvim_create_autocmd('BufEnter', { - desc = 'Track recent real file buffers for alternate-buffer jumps', - callback = function(args) - local buf = args.buf - - if is_real_file_buffer(buf) and buf ~= last_file_buf then - previous_file_buf = last_file_buf - last_file_buf = buf - end - end, -}) - --- Enable line numbers in netrw buffers -vim.api.nvim_create_autocmd('FileType', { - pattern = 'netrw', - desc = 'Configure netrw buffer-local options', - callback = function() - local buf = vim.api.nvim_get_current_buf() - vim.bo.buflisted = false - vim.opt_local.number = true - vim.opt_local.relativenumber = true - - -- netrw installs its own buffer mappings while building the listing. - -- Apply the preview extension after that setup has finished. - vim.schedule(function() - if is_valid_buffer(buf) and vim.bo[buf].filetype == 'netrw' then - netrw_preview.setup(buf) - end - end) - end, -}) diff --git a/lua/netrw-preview.lua b/lua/netrw-preview.lua deleted file mode 100644 index cef3a1a..0000000 --- a/lua/netrw-preview.lua +++ /dev/null @@ -1,728 +0,0 @@ -local M = {} - -local uv = vim.uv -local states = {} -local preview_buffers = {} -local preview_group = vim.api.nvim_create_augroup('netrw_live_preview', { clear = true }) - -local DEBOUNCE_MS = 90 -local MAX_ENTRIES = 200 -local PREVIEW_BUFFER_CLEANUP_MS = 2000 - -local function is_valid_buffer(buf) - return type(buf) == 'number' and buf > 0 and vim.api.nvim_buf_is_valid(buf) -end - -local function is_valid_window(win) - return type(win) == 'number' and win > 0 and vim.api.nvim_win_is_valid(win) -end - -local function is_valid_tab(tab) - return type(tab) == 'number' and tab > 0 and vim.api.nvim_tabpage_is_valid(tab) -end - -local function is_remote_path(path) - return type(path) == 'string' and path:match('^%a[%w+.-]*://') ~= nil -end - -local function netrw_call(name, ...) - return pcall(vim.fn['netrw#Call'], name, ...) -end - -local function find_preview_window(tab) - if not is_valid_tab(tab) then - return nil - end - - for _, win in ipairs(vim.api.nvim_tabpage_list_wins(tab)) do - if is_valid_window(win) and vim.wo[win].previewwindow then - return win - end - end -end - -local function close_timer(state, key) - key = key or 'timer' - local timer = state and state[key] - if not timer then - return - end - - pcall(timer.stop, timer) - if not timer:is_closing() then - pcall(timer.close, timer) - end - state[key] = nil -end - -local function indent_guides_enabled(buf) - local ok, config = pcall(require, 'ibl.config') - if not ok or not config.config then - return nil - end - return config.get_config(buf).enabled -end - -local function set_indent_guides(buf, enabled) - if enabled == nil then - return - end - - local ok, ibl = pcall(require, 'ibl') - if ok and ibl.initialized then - ibl.setup_buffer(buf, { enabled = enabled }) - end -end - -local function restore_preview_buffer(buf, for_editing) - local metadata = preview_buffers[buf] - if not metadata or not is_valid_buffer(buf) then - return - end - - vim.b[buf].netrw_live_preview_buffer = nil - vim.bo[buf].bufhidden = metadata.bufhidden - vim.bo[buf].buflisted = for_editing or metadata.buflisted - vim.bo[buf].syntax = metadata.syntax - vim.diagnostic.enable(metadata.diagnostics_enabled, { bufnr = buf }) - set_indent_guides(buf, metadata.indent_guides_enabled) - if metadata.treesitter_active then - pcall(vim.treesitter.start, buf) - end - preview_buffers[buf] = nil -end - -local function schedule_preview_buffer_cleanup(state) - if not state or state.preview_cleanup_scheduled then - return - end - - state.preview_cleanup_scheduled = true - vim.defer_fn(function() - state.preview_cleanup_scheduled = false - - for buf, metadata in pairs(preview_buffers) do - local is_preview = is_valid_buffer(buf) and vim.b[buf].netrw_live_preview_buffer == true - local is_visible = is_valid_buffer(buf) and #vim.fn.win_findbuf(buf) > 0 - if not is_preview or not is_visible then - if is_preview and metadata.loaded then - restore_preview_buffer(buf, false) - end - if not is_preview then - preview_buffers[buf] = nil - end - end - end - end, PREVIEW_BUFFER_CLEANUP_MS) -end - -local function close_preview(state) - if not state then - return - end - - local preview = find_preview_window(state.tab) - if preview then - pcall(vim.api.nvim_win_close, preview, false) - schedule_preview_buffer_cleanup(state) - end -end - -local function normalize_local_path(path) - if type(path) ~= 'string' or path == '' then - return nil - end - - local trimmed = path:gsub('/+$', '') - if trimmed == '' and path:sub(1, 1) == '/' then - trimmed = '/' - end - return vim.fs.normalize(trimmed) -end - -local function selected_entry(buf, win) - if not is_valid_buffer(buf) or not is_valid_window(win) then - return nil, 'netrw buffer or window is no longer valid' - end - - return vim.api.nvim_win_call(win, function() - local curdir = vim.b[buf].netrw_curdir - local ok_word, word = netrw_call('NetrwGetWord') - if not ok_word or type(word) ~= 'string' or word == '' then - return nil, 'netrw could not identify the selected entry' - end - - if is_remote_path(curdir) then - return { - remote = true, - word = word, - } - end - - local path - if vim.w[win].netrw_liststyle == 3 and type(vim.w[win].netrw_treetop) == 'string' then - local ok_tree, tree_path = netrw_call('NetrwTreePath', vim.w[win].netrw_treetop) - if not ok_tree or type(tree_path) ~= 'string' or tree_path == '' then - return nil, 'netrw could not resolve the selected tree path' - end - - if word == '../' then - path = vim.fs.dirname(normalize_local_path(tree_path)) - elseif word:sub(-1) == '/' then - path = tree_path - else - path = vim.fs.joinpath(tree_path, (word:gsub('[@*]$', ''))) - end - else - local name = word:gsub('/$', ''):gsub('[@*]$', '') - path = vim.fs.isabs(name) and name or vim.fs.joinpath(curdir, name) - end - - return { - path = normalize_local_path(path), - remote = false, - word = word, - } - end) -end - -local function human_size(bytes) - if type(bytes) ~= 'number' then - return '—' - end - - local units = { 'B', 'K', 'M', 'G', 'T' } - local value = bytes - local unit = 1 - while value >= 1024 and unit < #units do - value = value / 1024 - unit = unit + 1 - end - - if unit == 1 then - return ('%d%s'):format(value, units[unit]) - end - - local formatted = ('%.1f'):format(value):gsub('%.0$', '') - return formatted .. units[unit] -end - -local function modified_time(stat) - local seconds = stat and stat.mtime and stat.mtime.sec - if type(seconds) ~= 'number' then - return '—' - end - - return os.date('%Y-%m-%d %H:%M', seconds) -end - -local function visible_in_netrw(name, entry_type) - local hide_mode = tonumber(vim.g.netrw_hide) or 0 - local pattern = vim.g.netrw_list_hide - if hide_mode == 0 or type(pattern) ~= 'string' or pattern == '' then - return true - end - - local candidate = name .. (entry_type == 'directory' and '/' or '') - local hidden = vim.fn.match(candidate, pattern) >= 0 - return (hide_mode == 1 and not hidden) or (hide_mode == 2 and hidden) -end - -local function entry_details(directory, name, hinted_type) - local path = vim.fs.joinpath(directory, name) - local stat = uv.fs_lstat(path) - local entry_type = stat and stat.type or hinted_type or 'unknown' - local display_name = name - local size = '—' - - if entry_type == 'directory' then - display_name = display_name .. '/' - elseif entry_type == 'file' then - size = human_size(stat and stat.size) - elseif entry_type == 'link' then - local target = uv.fs_readlink(path) - display_name = display_name .. '@' - if target then - display_name = display_name .. ' -> ' .. target - end - end - - return { - name = name, - display_name = display_name, - path = path, - type = entry_type, - size = size, - bytes = entry_type == 'file' and stat and stat.size or 0, - modified = modified_time(stat), - } -end - -local function plural(count, singular, plural_form) - return ('%d %s'):format(count, count == 1 and singular or plural_form) -end - -local function directory_lines(path) - local scan, scan_error = uv.fs_scandir(path) - if not scan then - return { - path .. '/', - '', - 'Unable to read directory:', - tostring(scan_error or 'unknown error'), - } - end - - local entries = {} - local counts = { directory = 0, file = 0, link = 0, other = 0 } - local total_file_size = 0 - - while true do - local name, hinted_type = uv.fs_scandir_next(scan) - if not name then - break - end - - if visible_in_netrw(name, hinted_type) then - local entry = entry_details(path, name, hinted_type) - if entry.type == 'directory' then - counts.directory = counts.directory + 1 - elseif entry.type == 'file' then - counts.file = counts.file + 1 - total_file_size = total_file_size + (entry.bytes or 0) - elseif entry.type == 'link' then - counts.link = counts.link + 1 - else - counts.other = counts.other + 1 - end - table.insert(entries, entry) - end - end - - local ranks = { directory = 1, file = 2, link = 3 } - table.sort(entries, function(a, b) - local a_rank = ranks[a.type] or 4 - local b_rank = ranks[b.type] or 4 - if a_rank ~= b_rank then - return a_rank < b_rank - end - return a.name:lower() < b.name:lower() - end) - - local lines = { - path == '/' and '/' or path .. '/', - '', - ('%-5s %8s %-16s %s'):format('Type', 'Size', 'Modified', 'Name'), - ('%-5s %8s %-16s %s'):format('-----', '--------', '----------------', '----'), - } - - for index, entry in ipairs(entries) do - if index > MAX_ENTRIES then - break - end - local label = entry.type == 'directory' and 'dir' - or entry.type == 'file' and 'file' - or entry.type == 'link' and 'link' - or 'other' - table.insert(lines, ('%-5s %8s %-16s %s'):format( - label, - entry.size, - entry.modified, - entry.display_name - )) - end - - if #entries == 0 then - table.insert(lines, '(empty)') - elseif #entries > MAX_ENTRIES then - table.insert(lines, ('… showing first %d of %d entries'):format(MAX_ENTRIES, #entries)) - end - - table.insert(lines, '') - local summary = { - plural(counts.directory, 'directory', 'directories'), - plural(counts.file, 'file', 'files'), - } - if counts.link > 0 then - table.insert(summary, plural(counts.link, 'link', 'links')) - end - if counts.other > 0 then - table.insert(summary, plural(counts.other, 'other entry', 'other entries')) - end - table.insert(lines, table.concat(summary, ', ') .. ', ' .. human_size(total_file_size) .. ' in immediate files') - - return lines -end - -local function symlink_lines(path, stat) - local target, read_error = uv.fs_readlink(path) - return { - path .. '@', - '', - 'Type: symbolic link', - 'Target: ' .. tostring(target or read_error or 'unavailable'), - 'Modified: ' .. modified_time(stat), - '', - 'The target is not traversed in directory previews.', - } -end - -local function unavailable_lines(path, error_message) - return { - tostring(path or '(unknown entry)'), - '', - 'Preview unavailable:', - tostring(error_message or 'entry no longer exists'), - } -end - -local function ensure_summary_buffer(state) - if is_valid_buffer(state.summary_buf) then - return state.summary_buf - end - - local buf = vim.api.nvim_create_buf(false, true) - vim.bo[buf].buftype = 'nofile' - vim.bo[buf].bufhidden = 'wipe' - vim.bo[buf].swapfile = false - vim.bo[buf].filetype = 'netrw-preview' - vim.b[buf].netrw_directory_preview = true - state.summary_buf = buf - return buf -end - -local function set_summary_lines(buf, lines) - vim.bo[buf].readonly = false - vim.bo[buf].modifiable = true - vim.api.nvim_buf_set_lines(buf, 0, -1, false, lines) - vim.bo[buf].modified = false - vim.bo[buf].modifiable = false - vim.bo[buf].readonly = true -end - -local function configure_summary_window(win) - vim.wo[win].previewwindow = true - vim.wo[win].number = false - vim.wo[win].relativenumber = false - vim.wo[win].cursorline = false - vim.wo[win].wrap = false - vim.wo[win].list = false - vim.wo[win].spell = false - vim.wo[win].signcolumn = 'no' -end - -local function show_summary(state, netrw_win, lines) - local buf = ensure_summary_buffer(state) - set_summary_lines(buf, lines) - - local preview = find_preview_window(state.tab) - if preview then - local ok = pcall(vim.api.nvim_win_set_buf, preview, buf) - if not ok then - return false - end - else - local ok, created = pcall(vim.api.nvim_open_win, buf, false, { - split = 'below', - win = netrw_win, - noautocmd = true, - }) - if not ok then - return false - end - preview = created - end - - configure_summary_window(preview) - vim.api.nvim_win_set_cursor(preview, { 1, 0 }) - return true -end - -local function native_preview(entry) - local path = entry.path - if entry.remote then - -- Match netrw's own `p` mapping arguments for local and remote listings. - local ok_path, resolved = netrw_call('NetrwBrowseChgDir', 1, entry.word, 1, 1) - if not ok_path then - return false - end - path = resolved - end - - if type(path) ~= 'string' or path == '' then - return false - end - - local ok = netrw_call('NetrwPreview', path) - return ok -end - -local function show_native_preview(state, entry) - state.native_preview_active = true - - local existing_buf = entry.path and vim.fn.bufnr(entry.path) or -1 - local existing = is_valid_buffer(existing_buf) and { - buf = existing_buf, - loaded = vim.api.nvim_buf_is_loaded(existing_buf), - buflisted = vim.bo[existing_buf].buflisted, - bufhidden = vim.bo[existing_buf].bufhidden, - syntax = vim.bo[existing_buf].syntax, - treesitter_active = vim.treesitter.highlighter.active[existing_buf] ~= nil, - diagnostics_enabled = vim.diagnostic.is_enabled({ bufnr = existing_buf }), - indent_guides_enabled = indent_guides_enabled(existing_buf), - } or nil - - local ok, shown = pcall(native_preview, entry) - - local preview = find_preview_window(state.tab) - if preview then - local preview_buf = vim.api.nvim_win_get_buf(preview) - local preview_only = #vim.fn.win_findbuf(preview_buf) == 1 - if vim.bo[preview_buf].buftype == '' and preview_only then - preview_buffers[preview_buf] = preview_buffers[preview_buf] or { - loaded = existing ~= nil and existing.buf == preview_buf and existing.loaded, - buflisted = existing ~= nil and existing.buf == preview_buf and existing.buflisted or false, - bufhidden = existing ~= nil and existing.buf == preview_buf and existing.bufhidden or '', - syntax = existing ~= nil and existing.buf == preview_buf and existing.syntax or '', - treesitter_active = existing ~= nil - and existing.buf == preview_buf - and existing.loaded - and existing.treesitter_active - or vim.treesitter.highlighter.active[preview_buf] ~= nil, - diagnostics_enabled = existing ~= nil - and existing.buf == preview_buf - and existing.diagnostics_enabled - or vim.diagnostic.is_enabled({ bufnr = preview_buf }), - indent_guides_enabled = existing ~= nil - and existing.buf == preview_buf - and existing.indent_guides_enabled - or indent_guides_enabled(preview_buf), - } - - vim.bo[preview_buf].bufhidden = 'hide' - vim.bo[preview_buf].buflisted = preview_buffers[preview_buf].buflisted - vim.b[preview_buf].netrw_live_preview_buffer = true - vim.diagnostic.enable(false, { bufnr = preview_buf }) - set_indent_guides(preview_buf, false) - end - end - - if is_valid_window(state.win) then - pcall(vim.api.nvim_set_current_win, state.win) - end - state.native_preview_active = false - return ok and shown -end - -local function preview_selected(state, allow_create) - if not state or not is_valid_buffer(state.buf) or not is_valid_window(state.win) then - return - end - - if vim.api.nvim_win_get_buf(state.win) ~= state.buf then - return - end - - if not find_preview_window(state.tab) and not allow_create then - return - end - - local entry, resolve_error = selected_entry(state.buf, state.win) - if not entry then - show_summary(state, state.win, unavailable_lines(nil, resolve_error)) - return - end - - if entry.remote then - show_native_preview(state, entry) - return - end - - local stat, stat_error = uv.fs_lstat(entry.path) - if not stat then - show_summary(state, state.win, unavailable_lines(entry.path, stat_error)) - return - end - - if stat.type == 'directory' then - show_summary(state, state.win, directory_lines(entry.path)) - elseif stat.type == 'link' then - show_summary(state, state.win, symlink_lines(entry.path, stat)) - elseif stat.type == 'file' then - show_native_preview(state, entry) - else - show_summary(state, state.win, unavailable_lines(entry.path, 'unsupported entry type: ' .. stat.type)) - end -end - -local function schedule_preview(state) - if not state then - return - end - - if not find_preview_window(state.tab) then - schedule_preview_buffer_cleanup(state) - return - end - - if not state.timer then - state.timer = uv.new_timer() - end - - state.timer:stop() - state.timer:start(DEBOUNCE_MS, 0, vim.schedule_wrap(function() - preview_selected(state, false) - end)) -end - -vim.api.nvim_create_autocmd('BufEnter', { - group = preview_group, - desc = 'Restore normal editing behavior for a file previously used as a netrw preview', - callback = function(args) - local buf = args.buf - if not is_valid_buffer(buf) or vim.b[buf].netrw_live_preview_buffer ~= true then - return - end - - local win = vim.api.nvim_get_current_win() - if is_valid_window(win) and vim.wo[win].previewwindow then - return - end - - if preview_buffers[buf] then - restore_preview_buffer(buf, true) - end - end, -}) - -local function state_for(buf) - local state = states[buf] - if not state then - state = { buf = buf } - states[buf] = state - end - return state -end - -local function schedule_leave_cleanup(state) - close_timer(state, 'leave_timer') - state.leave_timer = uv.new_timer() - state.leave_timer:start(20, 0, vim.schedule_wrap(function() - close_timer(state, 'leave_timer') - - if state.native_preview_active then - return - end - - local current_win = vim.api.nvim_get_current_win() - local still_in_explorer = is_valid_window(current_win) - and current_win == state.win - and vim.api.nvim_win_get_buf(current_win) == state.buf - if not still_in_explorer then - close_preview(state) - end - end)) -end - -local function scroll_preview(direction, count) - local preview = find_preview_window(vim.api.nvim_get_current_tabpage()) - if not preview then - return - end - - local key = vim.keycode(direction > 0 and '' or '') - pcall(vim.api.nvim_win_call, preview, function() - vim.cmd.normal({ args = { tostring(count) .. key }, bang = true }) - end) -end - -function M.setup(buf) - if vim.fn.has('nvim-0.12') == 0 or not is_valid_buffer(buf) then - return false - end - - if vim.b[buf].netrw_live_preview_configured then - return true - end - - if vim.fn.exists('*netrw#Call') ~= 1 then - return false - end - - vim.b[buf].netrw_live_preview_configured = true - local state = state_for(buf) - - vim.keymap.set('n', 'p', function() - state.win = vim.api.nvim_get_current_win() - state.tab = vim.api.nvim_get_current_tabpage() - - if find_preview_window(state.tab) then - close_timer(state) - close_preview(state) - return - end - - preview_selected(state, true) - end, { - buffer = buf, - desc = 'Netrw: Toggle preview and live updates', - nowait = true, - silent = true, - }) - - vim.keymap.set('n', '', function() - scroll_preview(1, vim.v.count1) - end, { - buffer = buf, - desc = 'Netrw: Scroll preview down', - nowait = true, - silent = true, - }) - - vim.keymap.set('n', '', function() - scroll_preview(-1, vim.v.count1) - end, { - buffer = buf, - desc = 'Netrw: Scroll preview up', - nowait = true, - silent = true, - }) - - vim.api.nvim_create_autocmd('CursorMoved', { - group = preview_group, - buffer = buf, - desc = 'Update an existing netrw preview after cursor movement', - callback = function() - state.win = vim.api.nvim_get_current_win() - state.tab = vim.api.nvim_get_current_tabpage() - schedule_preview(state) - end, - }) - - vim.api.nvim_create_autocmd({ 'BufLeave', 'WinLeave' }, { - group = preview_group, - buffer = buf, - desc = 'Close the netrw preview when leaving the explorer', - callback = function() - close_timer(state) - schedule_leave_cleanup(state) - end, - }) - - vim.api.nvim_create_autocmd('BufWipeout', { - group = preview_group, - buffer = buf, - once = true, - desc = 'Release netrw preview resources', - callback = function() - close_timer(state) - close_timer(state, 'leave_timer') - close_preview(state) - states[buf] = nil - end, - }) - - return true -end - -return M diff --git a/lua/paper-tonic-modern/colors.lua b/lua/paper-tonic-modern/colors.lua deleted file mode 100644 index 7096388..0000000 --- a/lua/paper-tonic-modern/colors.lua +++ /dev/null @@ -1,270 +0,0 @@ --- Paper Tonic Modern - Color Palette --- Extracted from original Paper Tonic colorscheme --- Supports both light (paper-like) and dark modes - -local M = {} - --- Color format: { hex, 256-color, ansi } --- hex: Hexadecimal color code for GUI (GVim/MacVim/terminal with true color) --- 256: Integer 0-255 for 256-color terminals --- ansi: ANSI color name for basic 16-color terminals - --- Detect current background mode -local is_dark = vim.o.background == 'dark' - --- ============================================================================ --- Background Colors --- ============================================================================ - -if is_dark then - -- Dark mode: soft dark backgrounds - M.bg = {'#27292c', 234, 'black'} - M.bg_darkest = {'#ffffff', 255, 'white'} -- Inverted: lightest for strong contrast - M.bg_ui = {'#353535', 236, 'darkgray'} -else - -- Light mode: pure white paper - M.bg = {'#ffffff', 255, 'white'} - M.bg_darkest = {'#505050', 244, 'gray'} - M.bg_ui = {'#efefef', 0, 'darkgray'} -end - --- ============================================================================ --- Highlight Backgrounds (general) --- ============================================================================ - -if is_dark then - -- Dark mode: lighter backgrounds for highlights - M.bg_hl_strong = {"#3a3a3a", 237, "darkgray"} - M.bg_hl = {"#2a2a2a", 236, "darkgray"} - M.bg_hl_weak = {"#252525", 235, "darkgray"} - - -- Special highlight backgrounds (cyan/blue tones) - M.bg_hl_special_strong = {"#1a4a5a", 24, "darkblue"} - M.bg_hl_special = {"#0a3a4a", 23, "darkblue"} - M.bg_hl_special_weak = {"#1a3545", 23, "darkblue"} - - -- Alternative special highlight (green tones) - M.bg_hl_special_alt_strong = {"#1a5a2a", 28, "darkgreen"} - M.bg_hl_special_alt = {"#0a4a1a", 22, "darkgreen"} -else - -- Light mode: neutral gray tones - M.bg_hl_strong = {"#dddddd", 17, "white"} - M.bg_hl = {"#eeeeee", 250, "white"} - M.bg_hl_weak = {"#f7f2f2", 250, "white"} - - -- Special highlight backgrounds (cyan/blue tones) - M.bg_hl_special_strong = {"#a3e0ff", 17, "cyan"} - M.bg_hl_special = {"#d4f0ff", 250, "cyan"} - M.bg_hl_special_weak = {"#e0eaff", 250, "cyan"} - - -- Alternative special highlight (green tones) - M.bg_hl_special_alt_strong = {"#74f283", 17, "cyan"} - M.bg_hl_special_alt = {"#bff2cd", 250, "cyan"} -end - --- ============================================================================ --- Status Backgrounds (error, success, modified, fail) --- ============================================================================ - -if is_dark then - -- Dark mode: darker tinted backgrounds - M.bg_error = {'#4a2020', 52, 'darkred'} - M.bg_error_weak = {'#3a1a1a', 52, 'darkred'} - M.bg_success = {'#1a3a1a', 22, 'darkgreen'} - M.bg_modified = {'#1a1a3a', 17, 'darkblue'} - M.bg_fail = {'#3a1a1a', 52, 'darkred'} -else - -- Light mode: light tinted backgrounds - M.bg_error = {'#ffd7d7', 196, 'white'} - M.bg_error_weak = {'#ffefef', 196, 'white'} - M.bg_success = {'#e0ece0', 196, 'white'} - M.bg_modified = {'#e0e0ec', 196, 'white'} - M.bg_fail = {'#ece0e0', 196, 'white'} -end - --- ============================================================================ --- Foreground Colors (text) --- ============================================================================ - -if is_dark then - -- Dark mode: light text (inverted from light mode) - M.fg_stronger = {'#e0e0e0', 253, 'white'} -- Lightest text - M.fg_strong = {'#c0c0c0', 250, 'white'} -- Light text - M.fg = {'#a0a0a0', 248, 'gray'} -- Normal text (default) - M.fg_weak = {'#808080', 244, 'gray'} -- Dimmer text (comments, less important) - M.fg_weaker = {'#606060', 241, 'darkgray'} -- Dimmest text (very subtle) - M.fg_exception = {'#d08080', 174, 'red'} -- Light reddish for errors/exceptions -else - -- Light mode: dark text on paper - M.fg_stronger = {'#444444', 236, 'darkgrey'} -- Darkest text - M.fg_strong = {'#666666', 236, 'darkgrey'} -- Dark text - M.fg = {'#8c8c8c', 244, 'gray'} -- Normal text (default) - M.fg_weak = {'#9d9d9d', 251, 'gray'} -- Light text (comments, less important) - M.fg_weaker = {'#bbbbbb', 251, 'gray'} -- Lightest text (very subtle) - M.fg_exception = {'#7c4444', 251, 'gray'} -- Reddish-brown for errors/exceptions -end - --- ============================================================================ --- Status Foreground Colors (Git/Diff - muted natural tones) --- ============================================================================ - -if is_dark then - -- Dark mode: lighter muted tones - M.success = {'#a0d0a0', 114, 'green'} -- Success/addition (muted green) - M.modified = {'#a0a0d0', 110, 'blue'} -- Modified/change (muted blue) - M.fail = {'#d0a0a0', 174, 'red'} -- Fail/deletion (muted red) -else - -- Light mode: natural muted colors - M.success = {'#89af89', 196, 'white'} -- Success/addition (muted green) - M.modified = {'#8989af', 196, 'white'} -- Modified/change (muted blue) - M.fail = {'#af8989', 196, 'white'} -- Fail/deletion (muted red) -end - --- ============================================================================ --- Quickfix/Location List Diagnostic Colors (Muted tones like git/diff) --- ============================================================================ - -if is_dark then - -- Dark mode: lighter muted tones - M.qf_error = {'#d07070', 167, 'red'} -- Error (lighter muted red) - M.qf_warn = {'#d0a080', 173, 'yellow'} -- Warning (muted orange) - M.qf_info = {'#80b0d0', 110, 'blue'} -- Info (muted blue) - M.qf_hint = {'#80d0d0', 116, 'cyan'} -- Hint (lighter muted cyan) -else - -- Light mode: darker muted tones - M.qf_error = {'#af3f3f', 196, 'white'} -- Error (darker muted red for more contrast) - M.qf_warn = {'#af7f5f', 196, 'white'} -- Warning (muted orange) - M.qf_info = {'#5f8faf', 196, 'white'} -- Info (muted blue) - M.qf_hint = {'#5fafaf', 196, 'white'} -- Hint (lighter muted blue) -end - --- ============================================================================ --- Diagnostic/Alert Colors (Fluorescent/Neon - intentionally jarring) --- ============================================================================ - --- These colors are designed to be NOTICED, not blend in with code --- Fluorescent/neon aesthetic --- In light mode: bright, synthetic, stands out on white paper ("highlighter marker") --- In dark mode: slightly toned down but still prominent - -if is_dark then - -- Dark mode: still bright but not as harsh - M.diag_error = {'#ff4488', 204, 'red'} -- Bright pink-red - M.diag_warn = {'#ff8833', 208, 'yellow'} -- Bright orange - M.diag_info = {'#44ccff', 81, 'cyan'} -- Bright cyan - M.diag_hint = {'#88ddff', 117, 'cyan'} -- Softer cyan - M.diag_hint_dark = {'#44aacc', 74, 'cyan'} -- Medium cyan - M.diag_weak = {'#ffaa66', 215, 'yellow'} -- Lighter orange - - -- Diagnostic backgrounds - M.bg_diag_error = {'#3a1a25', 52, 'darkred'} - M.bg_diag_warn = {'#3a2a1a', 58, 'brown'} - M.bg_diag_info = {'#1a2a3a', 17, 'darkblue'} - M.bg_diag_hint = {'#1a2f3a', 23, 'darkblue'} - - M.question = {'#44ccff', 81, 'cyan'} -else - -- Light mode: fluorescent colors for maximum visibility - M.diag_error = {'#ff0066', 197, 'red'} -- Hot pink-red (screams "error!") - M.diag_warn = {'#ff6600', 202, 'red'} -- Fluorescent orange (warnings) - M.diag_info = {'#00ccff', 45, 'cyan'} -- Bright fluorescent cyan (info) - M.diag_hint = {'#66e0ff', 81, 'cyan'} -- Softer fluorescent cyan (hint) - M.diag_hint_dark = {'#0099cc', 38, 'cyan'} -- Darker cyan for UI elements - M.diag_weak = {'#ff9933', 208, 'yellow'} -- Lighter orange (spelling, etc.) - - -- Diagnostic backgrounds - M.bg_diag_error = {'#ffe6f0', 224, 'white'} - M.bg_diag_warn = {'#fff0e6', 223, 'white'} - M.bg_diag_info = {'#e6f9ff', 195, 'white'} - M.bg_diag_hint = {'#f0fcff', 195, 'white'} - - M.question = {'#00ccff', 45, 'cyan'} -end - --- ============================================================================ --- Primary Accent Colors (brownish-red tones) --- ============================================================================ - --- Primary accent: For "base" languages --- Used for: PHP, JavaScript, Python, etc. -if is_dark then - -- Dark mode: lighter brownish-red tones - M.primary_stronger = {"#d0a0a0", 181, "white"} - M.primary_strong = {"#c09090", 181, "white"} - M.primary = {"#b08080", 138, "gray"} - M.primary_weak = {"#a07070", 131, "darkgray"} -else - -- Light mode: darker brownish-red tones - M.primary_stronger = {"#7f4b4b", 236, "black"} - M.primary_strong = {"#5a4444", 236, "black"} - M.primary = {"#6b5555", 244, "gray"} - M.primary_weak = {"#7c6666", 248, "darkgray"} -end - --- ============================================================================ --- Language-Specific Color Palettes (for mixed-language contexts) --- ============================================================================ - --- IMPORTANT: Each language maintains its color identity regardless of where it appears. --- A language always uses the same color, whether standalone or embedded in another language. --- This creates consistent visual language recognition across all contexts. --- --- Example: In a PHP file with HTML and CSS: --- - PHP code: primary (brownish-red) - everywhere, including blocks --- - HTML tags: c3 (blue) - everywhere, whether in .html or embedded in PHP --- - CSS rules: c2 (green) - everywhere, whether in .css or