Compare commits
1 Commits
v0.1.2
...
7640eddb97
Author | SHA1 | Date | |
---|---|---|---|
|
7640eddb97 |
14
CHANGELOG.md
14
CHANGELOG.md
@@ -6,23 +6,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [0.1.2] - 2025-08-08
|
||||
|
||||
### Added
|
||||
- default to current dir if no file could be found
|
||||
|
||||
### Other
|
||||
- should be space instead
|
||||
|
||||
## [0.1.1] - 2025-08-04
|
||||
|
||||
### Fixed
|
||||
- if path is empty default to `.`
|
||||
|
||||
## [0.1.0] - 2025-08-03
|
||||
|
||||
### Added
|
||||
- add open command
|
||||
- noil now handles open, and open in non-terminals via. /dev/tty
|
||||
- add file opener with chooser
|
||||
- update demo
|
||||
|
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -431,7 +431,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "noil"
|
||||
version = "0.1.1"
|
||||
version = "0.0.5"
|
||||
dependencies = [
|
||||
"ansi_term",
|
||||
"anyhow",
|
||||
|
@@ -3,7 +3,7 @@ members = ["crates/*"]
|
||||
resolver = "2"
|
||||
|
||||
[workspace.package]
|
||||
version = "0.1.2"
|
||||
version = "0.1.0"
|
||||
|
||||
[workspace.dependencies]
|
||||
noil = { path = "crates/noil" }
|
||||
|
73
README.md
73
README.md
@@ -1,11 +1,8 @@
|
||||
# noil
|
||||
|
||||
**noil** is a structured, text-buffer-based file operation tool – think of it
|
||||
like [`oil.nvim`](https://github.com/stevearc/oil.nvim), but for any editor,
|
||||
terminal, or automated process.
|
||||
**noil** is a structured, text-buffer-based file operation tool – think of it like [`oil.nvim`](https://github.com/stevearc/oil.nvim), but for any editor, terminal, or automated process.
|
||||
|
||||
Edit filesystem operations like it's plain text, and then apply them in a
|
||||
controlled, explicit way.
|
||||
Edit filesystem operations like it's plain text, and then apply them in a controlled, explicit way.
|
||||
|
||||

|
||||
|
||||
@@ -13,19 +10,17 @@ controlled, explicit way.
|
||||
|
||||
## Interactive Mode (TBA)
|
||||
|
||||
I am planning an interactive TUI mode, where you don't have to care about tags,
|
||||
like in `oil`. For now the normal editor is quite useful though, and allows all
|
||||
types of editors to easily move, edit files and so on.
|
||||
I am planning an interactive TUI mode, where you don't have to care about tags, like in `oil`. For now the normal editor is quite useful though, and allows all types of editors to easily move, edit files and so on.
|
||||
|
||||
---
|
||||
|
||||
## ✨ Features
|
||||
|
||||
- Edit your file tree like a normal buffer
|
||||
- Preview, format, and apply changes
|
||||
- Integrates with `$EDITOR`
|
||||
- CLI first, editor agnostic
|
||||
- No surprises: nothing is applied until you say so
|
||||
* Edit your file tree like a normal buffer
|
||||
* Preview, format, and apply changes
|
||||
* Integrates with `$EDITOR`
|
||||
* CLI first, editor agnostic
|
||||
* No surprises: nothing is applied until you say so
|
||||
|
||||
---
|
||||
|
||||
@@ -47,7 +42,7 @@ cat something.noil | noil fmt > something.noil
|
||||
cat something.noil | noil apply
|
||||
```
|
||||
|
||||
noil will ask you if you want to apply your changes before doing any operations.
|
||||
noil will always ask you if you want to apply your changes before doing any operations.
|
||||
|
||||
---
|
||||
|
||||
@@ -61,14 +56,13 @@ Each line follows this format:
|
||||
|
||||
### Supported operations:
|
||||
|
||||
| Operation | Meaning | Tag Required? |
|
||||
| --------: | ------------------------------------------------------ | ------------- |
|
||||
| `ADD` | Add new file | ❌ No |
|
||||
| `COPY` | Copy file with given tag | ✅ Yes |
|
||||
| `DELETE` | Delete file with given tag | ✅ Yes |
|
||||
| `MOVE` | Move file with given tag | ✅ Yes |
|
||||
| `OPEN` | Open a file with a given tag (requires --chooser-file) | ❌ No |
|
||||
| _(blank)_ | Reference existing file (default) | ✅ Yes |
|
||||
| Operation | Meaning | Tag Required? |
|
||||
| --------: | --------------------------------- | ------------- |
|
||||
| `ADD` | Add new file | ❌ No |
|
||||
| `COPY` | Copy file with given tag | ✅ Yes |
|
||||
| `DELETE` | Delete file with given tag | ✅ Yes |
|
||||
| `MOVE` | Move file with given tag | ✅ Yes |
|
||||
| *(blank)* | Reference existing file (default) | ✅ Yes |
|
||||
|
||||
---
|
||||
|
||||
@@ -79,11 +73,9 @@ Each line follows this format:
|
||||
COPY abc : /tmp/nginx-copy
|
||||
DELETE 123 : /etc/nginx
|
||||
ADD : /new/file.txt
|
||||
OPEN : /new/file.txt
|
||||
```
|
||||
|
||||
You can use short, unique tags (like `abc`, `ng1`, etc.) to refer to files.
|
||||
`noil` will generate these tags when you run `noil .`.
|
||||
You can use short, unique tags (like `abc`, `ng1`, etc.) to refer to files. `noil` will generate these tags when you run `noil .`.
|
||||
|
||||
---
|
||||
|
||||
@@ -95,11 +87,9 @@ Want to clean up alignment and spacing?
|
||||
cat my-buffer.noil | noil fmt
|
||||
```
|
||||
|
||||
Or automatically format inside your editor with the following config for
|
||||
[Helix](https://helix-editor.com):
|
||||
Or automatically format inside your editor with the following config for [Helix](https://helix-editor.com):
|
||||
|
||||
```toml
|
||||
# .config/helix/languages.toml
|
||||
[[language]]
|
||||
name = "noil"
|
||||
scope = "source.noil"
|
||||
@@ -112,30 +102,8 @@ formatter = { command = "noil", args = ["fmt"] }
|
||||
[[grammar]]
|
||||
name = "noil"
|
||||
source = { git = "https://git.kjuulh.io/kjuulh/tree-sitter-noil.git", rev = "2f295629439881d0b9e89108a1296881d0daf7b9" }
|
||||
|
||||
# .config/helix/config.toml
|
||||
# Optional extra command Space + o will open noil allowing edits and the OPEN command
|
||||
[keys.normal.space]
|
||||
o = [
|
||||
":sh rm -f /tmp/unique-file-kjuulh",
|
||||
# DISCLAIMER: Until noil has a proper interactive mode, we cannot ask for confirmation, as such we always commit changes, you don't get to have a preview unlike the normal cli option
|
||||
":insert-output noil edit '%{buffer_name}' --chooser-file=/tmp/unique-file-kjuulh --commit --quiet < /dev/tty",
|
||||
":insert-output echo \"x1b[?1049h\" > /dev/tty",
|
||||
":open %sh{cat /tmp/unique-file-kjuulh}",
|
||||
":redraw",
|
||||
]
|
||||
```
|
||||
|
||||
### Edit options
|
||||
|
||||
When using `noil edit .` a few additional options are available
|
||||
|
||||
- `--chooser-file`: A chooser file is a newline delimited file where each line
|
||||
corresponds to a relative file to be opened or manipulated by the user. Only
|
||||
items with `OPEN` command will be added to the file
|
||||
- `--commit`: commit files without asking for confirmation
|
||||
- `--quiet`: don't print results
|
||||
|
||||
---
|
||||
|
||||
## 🔒 Safety First
|
||||
@@ -155,9 +123,7 @@ You will be prompted before anything is modified.
|
||||
|
||||
## 🧠 Philosophy
|
||||
|
||||
noil gives you full control over file operations in a composable and
|
||||
editor-friendly way. Think Git index, but for actual file moves and deletions —
|
||||
human-editable, patchable, and grep-able.
|
||||
noil gives you full control over file operations in a composable and editor-friendly way. Think Git index, but for actual file moves and deletions — human-editable, patchable, and grep-able.
|
||||
|
||||
---
|
||||
|
||||
@@ -169,6 +135,7 @@ human-editable, patchable, and grep-able.
|
||||
cargo install noil
|
||||
```
|
||||
|
||||
|
||||
**Build from source**:
|
||||
|
||||
```bash
|
||||
|
@@ -40,13 +40,10 @@ pub struct EditCommand {
|
||||
|
||||
impl EditCommand {
|
||||
pub async fn execute(&self) -> anyhow::Result<()> {
|
||||
let mut small_id = Vec::new();
|
||||
|
||||
for _ in 0..8 {
|
||||
small_id.push(
|
||||
encode_rand::ALPHABET
|
||||
[rand::random_range(0..(encode_rand::ALPHABET_LEN as u8)) as usize],
|
||||
);
|
||||
let mut small_id = Vec::with_capacity(8);
|
||||
for id in small_id.iter_mut() {
|
||||
*id = encode_rand::ALPHABET
|
||||
[rand::random_range(0..(encode_rand::ALPHABET_LEN as u8)) as usize];
|
||||
}
|
||||
let small_id = String::from_utf8_lossy(&small_id);
|
||||
|
||||
@@ -65,20 +62,9 @@ impl EditCommand {
|
||||
.await
|
||||
.context("create temp file for noil")?;
|
||||
|
||||
let path = &self
|
||||
.get_path()
|
||||
let output = get_outputs(&self.get_path().await.context("get path")?, true)
|
||||
.await
|
||||
.context("get path")
|
||||
.inspect_err(|e| {
|
||||
tracing::warn!(
|
||||
"error: file path doesn't exist, defaulting to current working dir: {e}"
|
||||
)
|
||||
})
|
||||
.unwrap_or_else(|_| PathBuf::from("."));
|
||||
|
||||
let output = get_outputs(path, true)
|
||||
.await
|
||||
.context(format!("get output: {}", path.display()))?;
|
||||
.context("get output")?;
|
||||
file.write_all(output.as_bytes())
|
||||
.await
|
||||
.context("write contents for edit")?;
|
||||
@@ -165,16 +151,10 @@ impl EditCommand {
|
||||
}
|
||||
|
||||
if path.is_file() {
|
||||
let parent_path = path
|
||||
return path
|
||||
.parent()
|
||||
.map(|p| p.to_path_buf())
|
||||
.ok_or(anyhow::anyhow!("parent doesn't exist for file"))?;
|
||||
|
||||
if parent_path.display().to_string() == "" {
|
||||
return Ok(PathBuf::from("."));
|
||||
}
|
||||
|
||||
return Ok(parent_path);
|
||||
.ok_or(anyhow::anyhow!("parent doesn't exist for file"));
|
||||
}
|
||||
|
||||
Ok(path.clone())
|
||||
@@ -354,7 +334,7 @@ pub async fn apply(input: &str, options: ApplyOptions) -> anyhow::Result<()> {
|
||||
.map(|i| i.display().to_string())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
file.write_all(open_files.join(" ").as_bytes())
|
||||
file.write_all(open_files.join("\n").as_bytes())
|
||||
.await
|
||||
.context("write chosen files")?;
|
||||
file.flush().await.context("flush chosen file")?;
|
||||
|
Reference in New Issue
Block a user