Repository files navigation

🐍 pathlib.nvim

OS independent, ultimate solution to path handling in neovim.

NeovimLua

MLP-2.0IssuesBuild StatusLuaRocks

🐍 pathlib.nvim

This plugin aims to decrease the difficulties of path management across mutliple OSs in neovim. The plugin API is heavily inspired by Python's pathlib.Path with tweaks to fit neovim usage.

✨ Benefits

📦 Intuitive and Useful Methods

localPath=require("pathlib")
localdir=Path("~/Documents") -- Same as `Path.home() / "Documents"`localfoo=dir/"foo.txt"print(foo:basename(), foo:stem(), foo:suffix()) -- foo.txt, foo, .txtprint(foo:parent()) -- "/home/user/Documents"

📋 Git Integration

localgit_root=Path("/path/to/git/workdir")
assert(git_root:child(".git"):exists(), string.format("%s is not a git repo.", git_root))
require("pathlib.git").fill_git_state({ file_a, file_b, ... })
file_a.git_state.ignored-- is git ignoredfile_a.git_state.status-- git status (modified, added, staged, ...)file_a.git_state.git_root-- root directory of the repo

⏱️ Sync / Async Operations

The API is designed so it is very easy to switch between sync and async operations. Call them inside a nvim-nio async context without any change, and the operations are converted to be async (does not block the main thread).

localfoo=Path("~/Documents/foo.txt")
localcontent="File Content\n"-- # synclocalsync_bytes=foo:fs_write(content)
assert(sync_bytes==content:len(), foo.error_msg)
-- # asyncrequire("nio").run(function()
localasync_bytes=foo:fs_write(content)
assert(async_bytes==content:len(), foo.error_msg)
end)

🚀 Usage Example

Create Path Object

localPath=require("pathlib")
localcwd=Path.cwd()
vim.print(string.format([[cwd: %s]], cwd))
-- Use __div to chain file tree!localfolder=Path(".") /"folder"localfoo=folder/"foo.txt"assert(tostring(foo) =="folder/foo.txt") -- $PWD/folder/foo.txtassert(tostring(foo:parent()) =="folder")
-- Path object is comparableassert(foo==Path("./folder/foo.txt")) -- Path object can be created with argumentsassert(foo==Path(folder, "foo.txt")) -- Unpack any of them if you want!-- Calculate relativilyassert(foo:is_relative_to(Path("folder")))
assert(notfoo:is_relative_to(Path("./different folder")))
assert(foo:relative_to(folder) ==Path("foo.txt"))

Path object is stored with string[].

  • Very fast operations to work with parents / children / siblings.
  • No need to worry about path separator => OS Independent.
    • /: Unix, \: Windows

Nicely integrated with vim functions.

There are wrappers around vim functions such as fnamemodify, stdpath and getcwd.

path:modify(":p:t:r") -- vim.fn.fnamemodify-- Define child directory of stdpathsPath.stdpath("data", "mason", "bin") -- vim.fn.stdpath("data") .. "/mason/bin"

Create and Manipulate Files / Directories

localluv=vim.looplocalPath=require("pathlib")
-- Create new folderlocalnew_file=Path.new("./new/folder/foo.txt")
new_file:parent_assert():mkdir(Path.permission("rwxr-xr-x"), true) -- (permission, recursive)-- Create new file and write to itlocalfd=new_file:fs_open("w", Path.permission("rw-r--r--"), true)
assert(fd~=nil, "File creation failed. " ..new_file.error_msg)
luv.fs_write(fd, "File Content\n")
luv.fs_close(fd)
-- HINT: new_file:fs_write(...) does this all at once.-- SHORTHAND: read file content with `io.read`localcontent=new_file:io_read()
assert(content=="File Content\n")
-- SHORTHAND: write to filenew_file:io_write("File Content\n")
new_file:copy(new_file:with_basename("bar.txt")) -- copy `foo.txt` to `bar.txt`new_file:symlink_to(new_file:with_basename("baz.txt")) -- create symlink of `foo.txt` named `baz.txt`

Scan Directories

-- Continue from aboveforpathinnew_file:parent_assert():fs_iterdir() do-- loop: [Path("./new/folder/foo.txt"), Path("./new/folder/bar.txt"), Path("./new/folder/baz.txt")]end

Async Execution

This library uses nvim-nio under the hood to run async calls. Supported methods will turn into async calls inside a nio.run async context and has the EXACT SAME INTERFACE.

localnio=require("nio")
localpath=Path("foo.txt")
nio.run(function() -- async run (does not block the main thread)vim.print(path:fs_stat()) -- coroutine (async)path:fs_write("File Content\n") -- coroutine (async)vim.print(path:fs_read()) -- coroutine (async)vim.print("async done") -- prints lastend)
vim.print("sync here") -- prints first (maybe not if above functions end very fast)

When execution fails, function will return nil and the error message is captured into self.error_msg. This property holds the error message of the latest async function call.

nio.run(function ()
localpath=Path("./does/not/exist.txt")
localfd=path:fs_open("r")
assert(fd, "ERROR: " ..path.error_msg)
-- fd will be nil when `:fs_open` fails. Check `self.error_msg` for the error message.end)

TODO

  • API documentation.
    • PathlibPath
    • PathlibPosixPath
    • PathlibWindowsPath
    • Git
  • Git operation integration.
  • Git test suite.
    • List out every possible git state: ignored, staged etc.
    • Create file for each state.
    • Add docs for each state: man git-diff -> RAW OUTPUT FORMAT
  • Windows implementation, test environment.
    • Create a CI/CD action to run on windows.
    • Prepare windows specific test suite.

Contributions

I'll happily accept any feature request Feel free to ask for any functionality :)

Other Projects

About

Ultimate solution to path handling in neovim. OS Independent.

Resources

Stars

76 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Repository files navigation

🐍 pathlib.nvim

OS independent, ultimate solution to path handling in neovim.

NeovimLua

MLP-2.0IssuesBuild StatusLuaRocks

🐍 pathlib.nvim

This plugin aims to decrease the difficulties of path management across mutliple OSs in neovim. The plugin API is heavily inspired by Python's pathlib.Path with tweaks to fit neovim usage.

✨ Benefits

📦 Intuitive and Useful Methods

localPath=require("pathlib")
localdir=Path("~/Documents") -- Same as `Path.home() / "Documents"`localfoo=dir/"foo.txt"print(foo:basename(), foo:stem(), foo:suffix()) -- foo.txt, foo, .txtprint(foo:parent()) -- "/home/user/Documents"

📋 Git Integration

localgit_root=Path("/path/to/git/workdir")
assert(git_root:child(".git"):exists(), string.format("%s is not a git repo.", git_root))
require("pathlib.git").fill_git_state({ file_a, file_b, ... })
file_a.git_state.ignored-- is git ignoredfile_a.git_state.status-- git status (modified, added, staged, ...)file_a.git_state.git_root-- root directory of the repo

⏱️ Sync / Async Operations

The API is designed so it is very easy to switch between sync and async operations. Call them inside a nvim-nio async context without any change, and the operations are converted to be async (does not block the main thread).

localfoo=Path("~/Documents/foo.txt")
localcontent="File Content\n"-- # synclocalsync_bytes=foo:fs_write(content)
assert(sync_bytes==content:len(), foo.error_msg)
-- # asyncrequire("nio").run(function()
localasync_bytes=foo:fs_write(content)
assert(async_bytes==content:len(), foo.error_msg)
end)

🚀 Usage Example

Create Path Object

localPath=require("pathlib")
localcwd=Path.cwd()
vim.print(string.format([[cwd: %s]], cwd))
-- Use __div to chain file tree!localfolder=Path(".") /"folder"localfoo=folder/"foo.txt"assert(tostring(foo) =="folder/foo.txt") -- $PWD/folder/foo.txtassert(tostring(foo:parent()) =="folder")
-- Path object is comparableassert(foo==Path("./folder/foo.txt")) -- Path object can be created with argumentsassert(foo==Path(folder, "foo.txt")) -- Unpack any of them if you want!-- Calculate relativilyassert(foo:is_relative_to(Path("folder")))
assert(notfoo:is_relative_to(Path("./different folder")))
assert(foo:relative_to(folder) ==Path("foo.txt"))

Path object is stored with string[].

  • Very fast operations to work with parents / children / siblings.
  • No need to worry about path separator => OS Independent.
    • /: Unix, \: Windows

Nicely integrated with vim functions.

There are wrappers around vim functions such as fnamemodify, stdpath and getcwd.

path:modify(":p:t:r") -- vim.fn.fnamemodify-- Define child directory of stdpathsPath.stdpath("data", "mason", "bin") -- vim.fn.stdpath("data") .. "/mason/bin"

Create and Manipulate Files / Directories

localluv=vim.looplocalPath=require("pathlib")
-- Create new folderlocalnew_file=Path.new("./new/folder/foo.txt")
new_file:parent_assert():mkdir(Path.permission("rwxr-xr-x"), true) -- (permission, recursive)-- Create new file and write to itlocalfd=new_file:fs_open("w", Path.permission("rw-r--r--"), true)
assert(fd~=nil, "File creation failed. " ..new_file.error_msg)
luv.fs_write(fd, "File Content\n")
luv.fs_close(fd)
-- HINT: new_file:fs_write(...) does this all at once.-- SHORTHAND: read file content with `io.read`localcontent=new_file:io_read()
assert(content=="File Content\n")
-- SHORTHAND: write to filenew_file:io_write("File Content\n")
new_file:copy(new_file:with_basename("bar.txt")) -- copy `foo.txt` to `bar.txt`new_file:symlink_to(new_file:with_basename("baz.txt")) -- create symlink of `foo.txt` named `baz.txt`

Scan Directories

-- Continue from aboveforpathinnew_file:parent_assert():fs_iterdir() do-- loop: [Path("./new/folder/foo.txt"), Path("./new/folder/bar.txt"), Path("./new/folder/baz.txt")]end

Async Execution

This library uses nvim-nio under the hood to run async calls. Supported methods will turn into async calls inside a nio.run async context and has the EXACT SAME INTERFACE.

localnio=require("nio")
localpath=Path("foo.txt")
nio.run(function() -- async run (does not block the main thread)vim.print(path:fs_stat()) -- coroutine (async)path:fs_write("File Content\n") -- coroutine (async)vim.print(path:fs_read()) -- coroutine (async)vim.print("async done") -- prints lastend)
vim.print("sync here") -- prints first (maybe not if above functions end very fast)

When execution fails, function will return nil and the error message is captured into self.error_msg. This property holds the error message of the latest async function call.

nio.run(function ()
localpath=Path("./does/not/exist.txt")
localfd=path:fs_open("r")
assert(fd, "ERROR: " ..path.error_msg)
-- fd will be nil when `:fs_open` fails. Check `self.error_msg` for the error message.end)

TODO

  • API documentation.
    • PathlibPath
    • PathlibPosixPath
    • PathlibWindowsPath
    • Git
  • Git operation integration.
  • Git test suite.
    • List out every possible git state: ignored, staged etc.
    • Create file for each state.
    • Add docs for each state: man git-diff -> RAW OUTPUT FORMAT
  • Windows implementation, test environment.
    • Create a CI/CD action to run on windows.
    • Prepare windows specific test suite.

Contributions

I'll happily accept any feature request Feel free to ask for any functionality :)

Other Projects

About

Ultimate solution to path handling in neovim. OS Independent.

Resources

Stars

76 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

🐍 pathlib.nvim

OS independent, ultimate solution to path handling in neovim.

NeovimLua

MLP-2.0IssuesBuild StatusLuaRocks

🐍 pathlib.nvim

This plugin aims to decrease the difficulties of path management across mutliple OSs in neovim. The plugin API is heavily inspired by Python's pathlib.Path with tweaks to fit neovim usage.

✨ Benefits

📦 Intuitive and Useful Methods

localPath=require("pathlib")
localdir=Path("~/Documents") -- Same as `Path.home() / "Documents"`localfoo=dir/"foo.txt"print(foo:basename(), foo:stem(), foo:suffix()) -- foo.txt, foo, .txtprint(foo:parent()) -- "/home/user/Documents"

📋 Git Integration

localgit_root=Path("/path/to/git/workdir")
assert(git_root:child(".git"):exists(), string.format("%s is not a git repo.", git_root))
require("pathlib.git").fill_git_state({ file_a, file_b, ... })
file_a.git_state.ignored-- is git ignoredfile_a.git_state.status-- git status (modified, added, staged, ...)file_a.git_state.git_root-- root directory of the repo

⏱️ Sync / Async Operations

The API is designed so it is very easy to switch between sync and async operations. Call them inside a nvim-nio async context without any change, and the operations are converted to be async (does not block the main thread).

localfoo=Path("~/Documents/foo.txt")
localcontent="File Content\n"-- # synclocalsync_bytes=foo:fs_write(content)
assert(sync_bytes==content:len(), foo.error_msg)
-- # asyncrequire("nio").run(function()
localasync_bytes=foo:fs_write(content)
assert(async_bytes==content:len(), foo.error_msg)
end)

🚀 Usage Example

Create Path Object

localPath=require("pathlib")
localcwd=Path.cwd()
vim.print(string.format([[cwd: %s]], cwd))
-- Use __div to chain file tree!localfolder=Path(".") /"folder"localfoo=folder/"foo.txt"assert(tostring(foo) =="folder/foo.txt") -- $PWD/folder/foo.txtassert(tostring(foo:parent()) =="folder")
-- Path object is comparableassert(foo==Path("./folder/foo.txt")) -- Path object can be created with argumentsassert(foo==Path(folder, "foo.txt")) -- Unpack any of them if you want!-- Calculate relativilyassert(foo:is_relative_to(Path("folder")))
assert(notfoo:is_relative_to(Path("./different folder")))
assert(foo:relative_to(folder) ==Path("foo.txt"))

Path object is stored with string[].

  • Very fast operations to work with parents / children / siblings.
  • No need to worry about path separator => OS Independent.
    • /: Unix, \: Windows

Nicely integrated with vim functions.

There are wrappers around vim functions such as fnamemodify, stdpath and getcwd.

path:modify(":p:t:r") -- vim.fn.fnamemodify-- Define child directory of stdpathsPath.stdpath("data", "mason", "bin") -- vim.fn.stdpath("data") .. "/mason/bin"

Create and Manipulate Files / Directories

localluv=vim.looplocalPath=require("pathlib")
-- Create new folderlocalnew_file=Path.new("./new/folder/foo.txt")
new_file:parent_assert():mkdir(Path.permission("rwxr-xr-x"), true) -- (permission, recursive)-- Create new file and write to itlocalfd=new_file:fs_open("w", Path.permission("rw-r--r--"), true)
assert(fd~=nil, "File creation failed. " ..new_file.error_msg)
luv.fs_write(fd, "File Content\n")
luv.fs_close(fd)
-- HINT: new_file:fs_write(...) does this all at once.-- SHORTHAND: read file content with `io.read`localcontent=new_file:io_read()
assert(content=="File Content\n")
-- SHORTHAND: write to filenew_file:io_write("File Content\n")
new_file:copy(new_file:with_basename("bar.txt")) -- copy `foo.txt` to `bar.txt`new_file:symlink_to(new_file:with_basename("baz.txt")) -- create symlink of `foo.txt` named `baz.txt`

Scan Directories

-- Continue from aboveforpathinnew_file:parent_assert():fs_iterdir() do-- loop: [Path("./new/folder/foo.txt"), Path("./new/folder/bar.txt"), Path("./new/folder/baz.txt")]end

Async Execution

This library uses nvim-nio under the hood to run async calls. Supported methods will turn into async calls inside a nio.run async context and has the EXACT SAME INTERFACE.

localnio=require("nio")
localpath=Path("foo.txt")
nio.run(function() -- async run (does not block the main thread)vim.print(path:fs_stat()) -- coroutine (async)path:fs_write("File Content\n") -- coroutine (async)vim.print(path:fs_read()) -- coroutine (async)vim.print("async done") -- prints lastend)
vim.print("sync here") -- prints first (maybe not if above functions end very fast)

When execution fails, function will return nil and the error message is captured into self.error_msg. This property holds the error message of the latest async function call.

nio.run(function ()
localpath=Path("./does/not/exist.txt")
localfd=path:fs_open("r")
assert(fd, "ERROR: " ..path.error_msg)
-- fd will be nil when `:fs_open` fails. Check `self.error_msg` for the error message.end)

TODO

  • API documentation.
    • PathlibPath
    • PathlibPosixPath
    • PathlibWindowsPath
    • Git
  • Git operation integration.
  • Git test suite.
    • List out every possible git state: ignored, staged etc.
    • Create file for each state.
    • Add docs for each state: man git-diff -> RAW OUTPUT FORMAT
  • Windows implementation, test environment.
    • Create a CI/CD action to run on windows.
    • Prepare windows specific test suite.

Contributions

I'll happily accept any feature request Feel free to ask for any functionality :)

Other Projects

About

Ultimate solution to path handling in neovim. OS Independent.

Resources

Stars

76 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

🐍 pathlib.nvim

OS independent, ultimate solution to path handling in neovim.

NeovimLua

MLP-2.0IssuesBuild StatusLuaRocks

🐍 pathlib.nvim

This plugin aims to decrease the difficulties of path management across mutliple OSs in neovim. The plugin API is heavily inspired by Python's pathlib.Path with tweaks to fit neovim usage.

✨ Benefits

📦 Intuitive and Useful Methods

localPath=require("pathlib")
localdir=Path("~/Documents") -- Same as `Path.home() / "Documents"`localfoo=dir/"foo.txt"print(foo:basename(), foo:stem(), foo:suffix()) -- foo.txt, foo, .txtprint(foo:parent()) -- "/home/user/Documents"

📋 Git Integration

localgit_root=Path("/path/to/git/workdir")
assert(git_root:child(".git"):exists(), string.format("%s is not a git repo.", git_root))
require("pathlib.git").fill_git_state({ file_a, file_b, ... })
file_a.git_state.ignored-- is git ignoredfile_a.git_state.status-- git status (modified, added, staged, ...)file_a.git_state.git_root-- root directory of the repo

⏱️ Sync / Async Operations

The API is designed so it is very easy to switch between sync and async operations. Call them inside a nvim-nio async context without any change, and the operations are converted to be async (does not block the main thread).

localfoo=Path("~/Documents/foo.txt")
localcontent="File Content\n"-- # synclocalsync_bytes=foo:fs_write(content)
assert(sync_bytes==content:len(), foo.error_msg)
-- # asyncrequire("nio").run(function()
localasync_bytes=foo:fs_write(content)
assert(async_bytes==content:len(), foo.error_msg)
end)

🚀 Usage Example

Create Path Object

localPath=require("pathlib")
localcwd=Path.cwd()
vim.print(string.format([[cwd: %s]], cwd))
-- Use __div to chain file tree!localfolder=Path(".") /"folder"localfoo=folder/"foo.txt"assert(tostring(foo) =="folder/foo.txt") -- $PWD/folder/foo.txtassert(tostring(foo:parent()) =="folder")
-- Path object is comparableassert(foo==Path("./folder/foo.txt")) -- Path object can be created with argumentsassert(foo==Path(folder, "foo.txt")) -- Unpack any of them if you want!-- Calculate relativilyassert(foo:is_relative_to(Path("folder")))
assert(notfoo:is_relative_to(Path("./different folder")))
assert(foo:relative_to(folder) ==Path("foo.txt"))

Path object is stored with string[].

  • Very fast operations to work with parents / children / siblings.
  • No need to worry about path separator => OS Independent.
    • /: Unix, \: Windows

Nicely integrated with vim functions.

There are wrappers around vim functions such as fnamemodify, stdpath and getcwd.

path:modify(":p:t:r") -- vim.fn.fnamemodify-- Define child directory of stdpathsPath.stdpath("data", "mason", "bin") -- vim.fn.stdpath("data") .. "/mason/bin"

Create and Manipulate Files / Directories

localluv=vim.looplocalPath=require("pathlib")
-- Create new folderlocalnew_file=Path.new("./new/folder/foo.txt")
new_file:parent_assert():mkdir(Path.permission("rwxr-xr-x"), true) -- (permission, recursive)-- Create new file and write to itlocalfd=new_file:fs_open("w", Path.permission("rw-r--r--"), true)
assert(fd~=nil, "File creation failed. " ..new_file.error_msg)
luv.fs_write(fd, "File Content\n")
luv.fs_close(fd)
-- HINT: new_file:fs_write(...) does this all at once.-- SHORTHAND: read file content with `io.read`localcontent=new_file:io_read()
assert(content=="File Content\n")
-- SHORTHAND: write to filenew_file:io_write("File Content\n")
new_file:copy(new_file:with_basename("bar.txt")) -- copy `foo.txt` to `bar.txt`new_file:symlink_to(new_file:with_basename("baz.txt")) -- create symlink of `foo.txt` named `baz.txt`

Scan Directories

-- Continue from aboveforpathinnew_file:parent_assert():fs_iterdir() do-- loop: [Path("./new/folder/foo.txt"), Path("./new/folder/bar.txt"), Path("./new/folder/baz.txt")]end

Async Execution

This library uses nvim-nio under the hood to run async calls. Supported methods will turn into async calls inside a nio.run async context and has the EXACT SAME INTERFACE.

localnio=require("nio")
localpath=Path("foo.txt")
nio.run(function() -- async run (does not block the main thread)vim.print(path:fs_stat()) -- coroutine (async)path:fs_write("File Content\n") -- coroutine (async)vim.print(path:fs_read()) -- coroutine (async)vim.print("async done") -- prints lastend)
vim.print("sync here") -- prints first (maybe not if above functions end very fast)

When execution fails, function will return nil and the error message is captured into self.error_msg. This property holds the error message of the latest async function call.

nio.run(function ()
localpath=Path("./does/not/exist.txt")
localfd=path:fs_open("r")
assert(fd, "ERROR: " ..path.error_msg)
-- fd will be nil when `:fs_open` fails. Check `self.error_msg` for the error message.end)

TODO

  • API documentation.
    • PathlibPath
    • PathlibPosixPath
    • PathlibWindowsPath
    • Git
  • Git operation integration.
  • Git test suite.
    • List out every possible git state: ignored, staged etc.
    • Create file for each state.
    • Add docs for each state: man git-diff -> RAW OUTPUT FORMAT
  • Windows implementation, test environment.
    • Create a CI/CD action to run on windows.
    • Prepare windows specific test suite.

Contributions

I'll happily accept any feature request Feel free to ask for any functionality :)

Other Projects

About

Ultimate solution to path handling in neovim. OS Independent.

Resources

Stars

76 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Repository files navigation

🐍 pathlib.nvim

OS independent, ultimate solution to path handling in neovim.

NeovimLua

MLP-2.0IssuesBuild StatusLuaRocks

🐍 pathlib.nvim

This plugin aims to decrease the difficulties of path management across mutliple OSs in neovim. The plugin API is heavily inspired by Python's pathlib.Path with tweaks to fit neovim usage.

✨ Benefits

📦 Intuitive and Useful Methods

localPath=require("pathlib")
localdir=Path("~/Documents") -- Same as `Path.home() / "Documents"`localfoo=dir/"foo.txt"print(foo:basename(), foo:stem(), foo:suffix()) -- foo.txt, foo, .txtprint(foo:parent()) -- "/home/user/Documents"

📋 Git Integration

localgit_root=Path("/path/to/git/workdir")
assert(git_root:child(".git"):exists(), string.format("%s is not a git repo.", git_root))
require("pathlib.git").fill_git_state({ file_a, file_b, ... })
file_a.git_state.ignored-- is git ignoredfile_a.git_state.status-- git status (modified, added, staged, ...)file_a.git_state.git_root-- root directory of the repo

⏱️ Sync / Async Operations

The API is designed so it is very easy to switch between sync and async operations. Call them inside a nvim-nio async context without any change, and the operations are converted to be async (does not block the main thread).

localfoo=Path("~/Documents/foo.txt")
localcontent="File Content\n"-- # synclocalsync_bytes=foo:fs_write(content)
assert(sync_bytes==content:len(), foo.error_msg)
-- # asyncrequire("nio").run(function()
localasync_bytes=foo:fs_write(content)
assert(async_bytes==content:len(), foo.error_msg)
end)

🚀 Usage Example

Create Path Object

localPath=require("pathlib")
localcwd=Path.cwd()
vim.print(string.format([[cwd: %s]], cwd))
-- Use __div to chain file tree!localfolder=Path(".") /"folder"localfoo=folder/"foo.txt"assert(tostring(foo) =="folder/foo.txt") -- $PWD/folder/foo.txtassert(tostring(foo:parent()) =="folder")
-- Path object is comparableassert(foo==Path("./folder/foo.txt")) -- Path object can be created with argumentsassert(foo==Path(folder, "foo.txt")) -- Unpack any of them if you want!-- Calculate relativilyassert(foo:is_relative_to(Path("folder")))
assert(notfoo:is_relative_to(Path("./different folder")))
assert(foo:relative_to(folder) ==Path("foo.txt"))

Path object is stored with string[].

  • Very fast operations to work with parents / children / siblings.
  • No need to worry about path separator => OS Independent.
    • /: Unix, \: Windows

Nicely integrated with vim functions.

There are wrappers around vim functions such as fnamemodify, stdpath and getcwd.

path:modify(":p:t:r") -- vim.fn.fnamemodify-- Define child directory of stdpathsPath.stdpath("data", "mason", "bin") -- vim.fn.stdpath("data") .. "/mason/bin"

Create and Manipulate Files / Directories

localluv=vim.looplocalPath=require("pathlib")
-- Create new folderlocalnew_file=Path.new("./new/folder/foo.txt")
new_file:parent_assert():mkdir(Path.permission("rwxr-xr-x"), true) -- (permission, recursive)-- Create new file and write to itlocalfd=new_file:fs_open("w", Path.permission("rw-r--r--"), true)
assert(fd~=nil, "File creation failed. " ..new_file.error_msg)
luv.fs_write(fd, "File Content\n")
luv.fs_close(fd)
-- HINT: new_file:fs_write(...) does this all at once.-- SHORTHAND: read file content with `io.read`localcontent=new_file:io_read()
assert(content=="File Content\n")
-- SHORTHAND: write to filenew_file:io_write("File Content\n")
new_file:copy(new_file:with_basename("bar.txt")) -- copy `foo.txt` to `bar.txt`new_file:symlink_to(new_file:with_basename("baz.txt")) -- create symlink of `foo.txt` named `baz.txt`

Scan Directories

-- Continue from aboveforpathinnew_file:parent_assert():fs_iterdir() do-- loop: [Path("./new/folder/foo.txt"), Path("./new/folder/bar.txt"), Path("./new/folder/baz.txt")]end

Async Execution

This library uses nvim-nio under the hood to run async calls. Supported methods will turn into async calls inside a nio.run async context and has the EXACT SAME INTERFACE.

localnio=require("nio")
localpath=Path("foo.txt")
nio.run(function() -- async run (does not block the main thread)vim.print(path:fs_stat()) -- coroutine (async)path:fs_write("File Content\n") -- coroutine (async)vim.print(path:fs_read()) -- coroutine (async)vim.print("async done") -- prints lastend)
vim.print("sync here") -- prints first (maybe not if above functions end very fast)

When execution fails, function will return nil and the error message is captured into self.error_msg. This property holds the error message of the latest async function call.

nio.run(function ()
localpath=Path("./does/not/exist.txt")
localfd=path:fs_open("r")
assert(fd, "ERROR: " ..path.error_msg)
-- fd will be nil when `:fs_open` fails. Check `self.error_msg` for the error message.end)

TODO

  • API documentation.
    • PathlibPath
    • PathlibPosixPath
    • PathlibWindowsPath
    • Git
  • Git operation integration.
  • Git test suite.
    • List out every possible git state: ignored, staged etc.
    • Create file for each state.
    • Add docs for each state: man git-diff -> RAW OUTPUT FORMAT
  • Windows implementation, test environment.
    • Create a CI/CD action to run on windows.
    • Prepare windows specific test suite.

Contributions

I'll happily accept any feature request Feel free to ask for any functionality :)

Other Projects

About

Ultimate solution to path handling in neovim. OS Independent.

Resources

Stars

76 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

🐍 pathlib.nvim

OS independent, ultimate solution to path handling in neovim.

NeovimLua

MLP-2.0IssuesBuild StatusLuaRocks

🐍 pathlib.nvim

This plugin aims to decrease the difficulties of path management across mutliple OSs in neovim. The plugin API is heavily inspired by Python's pathlib.Path with tweaks to fit neovim usage.

✨ Benefits

📦 Intuitive and Useful Methods

localPath=require("pathlib")
localdir=Path("~/Documents") -- Same as `Path.home() / "Documents"`localfoo=dir/"foo.txt"print(foo:basename(), foo:stem(), foo:suffix()) -- foo.txt, foo, .txtprint(foo:parent()) -- "/home/user/Documents"

📋 Git Integration

localgit_root=Path("/path/to/git/workdir")
assert(git_root:child(".git"):exists(), string.format("%s is not a git repo.", git_root))
require("pathlib.git").fill_git_state({ file_a, file_b, ... })
file_a.git_state.ignored-- is git ignoredfile_a.git_state.status-- git status (modified, added, staged, ...)file_a.git_state.git_root-- root directory of the repo

⏱️ Sync / Async Operations

The API is designed so it is very easy to switch between sync and async operations. Call them inside a nvim-nio async context without any change, and the operations are converted to be async (does not block the main thread).

localfoo=Path("~/Documents/foo.txt")
localcontent="File Content\n"-- # synclocalsync_bytes=foo:fs_write(content)
assert(sync_bytes==content:len(), foo.error_msg)
-- # asyncrequire("nio").run(function()
localasync_bytes=foo:fs_write(content)
assert(async_bytes==content:len(), foo.error_msg)
end)

🚀 Usage Example

Create Path Object

localPath=require("pathlib")
localcwd=Path.cwd()
vim.print(string.format([[cwd: %s]], cwd))
-- Use __div to chain file tree!localfolder=Path(".") /"folder"localfoo=folder/"foo.txt"assert(tostring(foo) =="folder/foo.txt") -- $PWD/folder/foo.txtassert(tostring(foo:parent()) =="folder")
-- Path object is comparableassert(foo==Path("./folder/foo.txt")) -- Path object can be created with argumentsassert(foo==Path(folder, "foo.txt")) -- Unpack any of them if you want!-- Calculate relativilyassert(foo:is_relative_to(Path("folder")))
assert(notfoo:is_relative_to(Path("./different folder")))
assert(foo:relative_to(folder) ==Path("foo.txt"))

Path object is stored with string[].

  • Very fast operations to work with parents / children / siblings.
  • No need to worry about path separator => OS Independent.
    • /: Unix, \: Windows

Nicely integrated with vim functions.

There are wrappers around vim functions such as fnamemodify, stdpath and getcwd.

path:modify(":p:t:r") -- vim.fn.fnamemodify-- Define child directory of stdpathsPath.stdpath("data", "mason", "bin") -- vim.fn.stdpath("data") .. "/mason/bin"

Create and Manipulate Files / Directories

localluv=vim.looplocalPath=require("pathlib")
-- Create new folderlocalnew_file=Path.new("./new/folder/foo.txt")
new_file:parent_assert():mkdir(Path.permission("rwxr-xr-x"), true) -- (permission, recursive)-- Create new file and write to itlocalfd=new_file:fs_open("w", Path.permission("rw-r--r--"), true)
assert(fd~=nil, "File creation failed. " ..new_file.error_msg)
luv.fs_write(fd, "File Content\n")
luv.fs_close(fd)
-- HINT: new_file:fs_write(...) does this all at once.-- SHORTHAND: read file content with `io.read`localcontent=new_file:io_read()
assert(content=="File Content\n")
-- SHORTHAND: write to filenew_file:io_write("File Content\n")
new_file:copy(new_file:with_basename("bar.txt")) -- copy `foo.txt` to `bar.txt`new_file:symlink_to(new_file:with_basename("baz.txt")) -- create symlink of `foo.txt` named `baz.txt`

Scan Directories

-- Continue from aboveforpathinnew_file:parent_assert():fs_iterdir() do-- loop: [Path("./new/folder/foo.txt"), Path("./new/folder/bar.txt"), Path("./new/folder/baz.txt")]end

Async Execution

This library uses nvim-nio under the hood to run async calls. Supported methods will turn into async calls inside a nio.run async context and has the EXACT SAME INTERFACE.

localnio=require("nio")
localpath=Path("foo.txt")
nio.run(function() -- async run (does not block the main thread)vim.print(path:fs_stat()) -- coroutine (async)path:fs_write("File Content\n") -- coroutine (async)vim.print(path:fs_read()) -- coroutine (async)vim.print("async done") -- prints lastend)
vim.print("sync here") -- prints first (maybe not if above functions end very fast)

When execution fails, function will return nil and the error message is captured into self.error_msg. This property holds the error message of the latest async function call.

nio.run(function ()
localpath=Path("./does/not/exist.txt")
localfd=path:fs_open("r")
assert(fd, "ERROR: " ..path.error_msg)
-- fd will be nil when `:fs_open` fails. Check `self.error_msg` for the error message.end)

TODO

  • API documentation.
    • PathlibPath
    • PathlibPosixPath
    • PathlibWindowsPath
    • Git
  • Git operation integration.
  • Git test suite.
    • List out every possible git state: ignored, staged etc.
    • Create file for each state.
    • Add docs for each state: man git-diff -> RAW OUTPUT FORMAT
  • Windows implementation, test environment.
    • Create a CI/CD action to run on windows.
    • Prepare windows specific test suite.

Contributions

I'll happily accept any feature request Feel free to ask for any functionality :)

Other Projects

About

Ultimate solution to path handling in neovim. OS Independent.

Resources

Stars

76 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

🐍 pathlib.nvim

OS independent, ultimate solution to path handling in neovim.

NeovimLua

MLP-2.0IssuesBuild StatusLuaRocks

🐍 pathlib.nvim

This plugin aims to decrease the difficulties of path management across mutliple OSs in neovim. The plugin API is heavily inspired by Python's pathlib.Path with tweaks to fit neovim usage.

✨ Benefits

📦 Intuitive and Useful Methods

localPath=require("pathlib")
localdir=Path("~/Documents") -- Same as `Path.home() / "Documents"`localfoo=dir/"foo.txt"print(foo:basename(), foo:stem(), foo:suffix()) -- foo.txt, foo, .txtprint(foo:parent()) -- "/home/user/Documents"

📋 Git Integration

localgit_root=Path("/path/to/git/workdir")
assert(git_root:child(".git"):exists(), string.format("%s is not a git repo.", git_root))
require("pathlib.git").fill_git_state({ file_a, file_b, ... })
file_a.git_state.ignored-- is git ignoredfile_a.git_state.status-- git status (modified, added, staged, ...)file_a.git_state.git_root-- root directory of the repo

⏱️ Sync / Async Operations

The API is designed so it is very easy to switch between sync and async operations. Call them inside a nvim-nio async context without any change, and the operations are converted to be async (does not block the main thread).

localfoo=Path("~/Documents/foo.txt")
localcontent="File Content\n"-- # synclocalsync_bytes=foo:fs_write(content)
assert(sync_bytes==content:len(), foo.error_msg)
-- # asyncrequire("nio").run(function()
localasync_bytes=foo:fs_write(content)
assert(async_bytes==content:len(), foo.error_msg)
end)

🚀 Usage Example

Create Path Object

localPath=require("pathlib")
localcwd=Path.cwd()
vim.print(string.format([[cwd: %s]], cwd))
-- Use __div to chain file tree!localfolder=Path(".") /"folder"localfoo=folder/"foo.txt"assert(tostring(foo) =="folder/foo.txt") -- $PWD/folder/foo.txtassert(tostring(foo:parent()) =="folder")
-- Path object is comparableassert(foo==Path("./folder/foo.txt")) -- Path object can be created with argumentsassert(foo==Path(folder, "foo.txt")) -- Unpack any of them if you want!-- Calculate relativilyassert(foo:is_relative_to(Path("folder")))
assert(notfoo:is_relative_to(Path("./different folder")))
assert(foo:relative_to(folder) ==Path("foo.txt"))

Path object is stored with string[].

  • Very fast operations to work with parents / children / siblings.
  • No need to worry about path separator => OS Independent.
    • /: Unix, \: Windows

Nicely integrated with vim functions.

There are wrappers around vim functions such as fnamemodify, stdpath and getcwd.

path:modify(":p:t:r") -- vim.fn.fnamemodify-- Define child directory of stdpathsPath.stdpath("data", "mason", "bin") -- vim.fn.stdpath("data") .. "/mason/bin"

Create and Manipulate Files / Directories

localluv=vim.looplocalPath=require("pathlib")
-- Create new folderlocalnew_file=Path.new("./new/folder/foo.txt")
new_file:parent_assert():mkdir(Path.permission("rwxr-xr-x"), true) -- (permission, recursive)-- Create new file and write to itlocalfd=new_file:fs_open("w", Path.permission("rw-r--r--"), true)
assert(fd~=nil, "File creation failed. " ..new_file.error_msg)
luv.fs_write(fd, "File Content\n")
luv.fs_close(fd)
-- HINT: new_file:fs_write(...) does this all at once.-- SHORTHAND: read file content with `io.read`localcontent=new_file:io_read()
assert(content=="File Content\n")
-- SHORTHAND: write to filenew_file:io_write("File Content\n")
new_file:copy(new_file:with_basename("bar.txt")) -- copy `foo.txt` to `bar.txt`new_file:symlink_to(new_file:with_basename("baz.txt")) -- create symlink of `foo.txt` named `baz.txt`

Scan Directories

-- Continue from aboveforpathinnew_file:parent_assert():fs_iterdir() do-- loop: [Path("./new/folder/foo.txt"), Path("./new/folder/bar.txt"), Path("./new/folder/baz.txt")]end

Async Execution

This library uses nvim-nio under the hood to run async calls. Supported methods will turn into async calls inside a nio.run async context and has the EXACT SAME INTERFACE.

localnio=require("nio")
localpath=Path("foo.txt")
nio.run(function() -- async run (does not block the main thread)vim.print(path:fs_stat()) -- coroutine (async)path:fs_write("File Content\n") -- coroutine (async)vim.print(path:fs_read()) -- coroutine (async)vim.print("async done") -- prints lastend)
vim.print("sync here") -- prints first (maybe not if above functions end very fast)

When execution fails, function will return nil and the error message is captured into self.error_msg. This property holds the error message of the latest async function call.

nio.run(function ()
localpath=Path("./does/not/exist.txt")
localfd=path:fs_open("r")
assert(fd, "ERROR: " ..path.error_msg)
-- fd will be nil when `:fs_open` fails. Check `self.error_msg` for the error message.end)

TODO

  • API documentation.
    • PathlibPath
    • PathlibPosixPath
    • PathlibWindowsPath
    • Git
  • Git operation integration.
  • Git test suite.
    • List out every possible git state: ignored, staged etc.
    • Create file for each state.
    • Add docs for each state: man git-diff -> RAW OUTPUT FORMAT
  • Windows implementation, test environment.
    • Create a CI/CD action to run on windows.
    • Prepare windows specific test suite.

Contributions

I'll happily accept any feature request Feel free to ask for any functionality :)

Other Projects

About

Ultimate solution to path handling in neovim. OS Independent.

Resources

Stars

76 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Repository files navigation

🐍 pathlib.nvim

OS independent, ultimate solution to path handling in neovim.

NeovimLua

MLP-2.0IssuesBuild StatusLuaRocks

🐍 pathlib.nvim

This plugin aims to decrease the difficulties of path management across mutliple OSs in neovim. The plugin API is heavily inspired by Python's pathlib.Path with tweaks to fit neovim usage.

✨ Benefits

📦 Intuitive and Useful Methods

localPath=require("pathlib")
localdir=Path("~/Documents") -- Same as `Path.home() / "Documents"`localfoo=dir/"foo.txt"print(foo:basename(), foo:stem(), foo:suffix()) -- foo.txt, foo, .txtprint(foo:parent()) -- "/home/user/Documents"

📋 Git Integration

localgit_root=Path("/path/to/git/workdir")
assert(git_root:child(".git"):exists(), string.format("%s is not a git repo.", git_root))
require("pathlib.git").fill_git_state({ file_a, file_b, ... })
file_a.git_state.ignored-- is git ignoredfile_a.git_state.status-- git status (modified, added, staged, ...)file_a.git_state.git_root-- root directory of the repo

⏱️ Sync / Async Operations

The API is designed so it is very easy to switch between sync and async operations. Call them inside a nvim-nio async context without any change, and the operations are converted to be async (does not block the main thread).

localfoo=Path("~/Documents/foo.txt")
localcontent="File Content\n"-- # synclocalsync_bytes=foo:fs_write(content)
assert(sync_bytes==content:len(), foo.error_msg)
-- # asyncrequire("nio").run(function()
localasync_bytes=foo:fs_write(content)
assert(async_bytes==content:len(), foo.error_msg)
end)

🚀 Usage Example

Create Path Object

localPath=require("pathlib")
localcwd=Path.cwd()
vim.print(string.format([[cwd: %s]], cwd))
-- Use __div to chain file tree!localfolder=Path(".") /"folder"localfoo=folder/"foo.txt"assert(tostring(foo) =="folder/foo.txt") -- $PWD/folder/foo.txtassert(tostring(foo:parent()) =="folder")
-- Path object is comparableassert(foo==Path("./folder/foo.txt")) -- Path object can be created with argumentsassert(foo==Path(folder, "foo.txt")) -- Unpack any of them if you want!-- Calculate relativilyassert(foo:is_relative_to(Path("folder")))
assert(notfoo:is_relative_to(Path("./different folder")))
assert(foo:relative_to(folder) ==Path("foo.txt"))

Path object is stored with string[].

  • Very fast operations to work with parents / children / siblings.
  • No need to worry about path separator => OS Independent.
    • /: Unix, \: Windows

Nicely integrated with vim functions.

There are wrappers around vim functions such as fnamemodify, stdpath and getcwd.

path:modify(":p:t:r") -- vim.fn.fnamemodify-- Define child directory of stdpathsPath.stdpath("data", "mason", "bin") -- vim.fn.stdpath("data") .. "/mason/bin"

Create and Manipulate Files / Directories

localluv=vim.looplocalPath=require("pathlib")
-- Create new folderlocalnew_file=Path.new("./new/folder/foo.txt")
new_file:parent_assert():mkdir(Path.permission("rwxr-xr-x"), true) -- (permission, recursive)-- Create new file and write to itlocalfd=new_file:fs_open("w", Path.permission("rw-r--r--"), true)
assert(fd~=nil, "File creation failed. " ..new_file.error_msg)
luv.fs_write(fd, "File Content\n")
luv.fs_close(fd)
-- HINT: new_file:fs_write(...) does this all at once.-- SHORTHAND: read file content with `io.read`localcontent=new_file:io_read()
assert(content=="File Content\n")
-- SHORTHAND: write to filenew_file:io_write("File Content\n")
new_file:copy(new_file:with_basename("bar.txt")) -- copy `foo.txt` to `bar.txt`new_file:symlink_to(new_file:with_basename("baz.txt")) -- create symlink of `foo.txt` named `baz.txt`

Scan Directories

-- Continue from aboveforpathinnew_file:parent_assert():fs_iterdir() do-- loop: [Path("./new/folder/foo.txt"), Path("./new/folder/bar.txt"), Path("./new/folder/baz.txt")]end

Async Execution

This library uses nvim-nio under the hood to run async calls. Supported methods will turn into async calls inside a nio.run async context and has the EXACT SAME INTERFACE.

localnio=require("nio")
localpath=Path("foo.txt")
nio.run(function() -- async run (does not block the main thread)vim.print(path:fs_stat()) -- coroutine (async)path:fs_write("File Content\n") -- coroutine (async)vim.print(path:fs_read()) -- coroutine (async)vim.print("async done") -- prints lastend)
vim.print("sync here") -- prints first (maybe not if above functions end very fast)

When execution fails, function will return nil and the error message is captured into self.error_msg. This property holds the error message of the latest async function call.

nio.run(function ()
localpath=Path("./does/not/exist.txt")
localfd=path:fs_open("r")
assert(fd, "ERROR: " ..path.error_msg)
-- fd will be nil when `:fs_open` fails. Check `self.error_msg` for the error message.end)

TODO

  • API documentation.
    • PathlibPath
    • PathlibPosixPath
    • PathlibWindowsPath
    • Git
  • Git operation integration.
  • Git test suite.
    • List out every possible git state: ignored, staged etc.
    • Create file for each state.
    • Add docs for each state: man git-diff -> RAW OUTPUT FORMAT
  • Windows implementation, test environment.
    • Create a CI/CD action to run on windows.
    • Prepare windows specific test suite.

Contributions

I'll happily accept any feature request Feel free to ask for any functionality :)

Other Projects

About

Ultimate solution to path handling in neovim. OS Independent.

Resources

Stars

76 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages