Skip to content

Commit 5922b90

Browse files
committed
v1.2.1
add: description to snippets meta fix: audit CI: add audit check
1 parent 1561327 commit 5922b90

10 files changed

Lines changed: 87 additions & 65 deletions

File tree

.cargo/audit.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[advisories]
2+
ignore = ["RUSTSEC-2026-0097"]

.github/workflows/test.yml

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ jobs:
1010
test:
1111
runs-on: ubuntu-latest
1212
steps:
13-
- uses: actions/checkout@v6
13+
- uses: actions/checkout@v6
1414

1515
- name: Install Rust
1616
uses: actions-rust-lang/setup-rust-toolchain@v1
@@ -27,4 +27,9 @@ jobs:
2727
run: cargo check
2828

2929
- name: Test
30-
run: cargo test
30+
run: cargo test
31+
32+
- name: Security audit
33+
run: |
34+
cargo install cargo-audit --quiet
35+
cargo audit

CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,17 @@ All notable changes to sinbo will be documented here.
44

55
---
66

7+
## 1.2.1 - 2026-04-11
8+
9+
### Added
10+
- Description field to snippet metadata
11+
12+
### Fixed
13+
- Suppressed false-positive `RUSTSEC-2026-0097` advisory for `rand 0.8.5` (unsoundness does not affect sinbo's usage)
14+
15+
### CI
16+
- Added `cargo audit` check to the pipeline
17+
718
## 1.2.0 - 2026-04-10
819

920
### Added

Cargo.lock

Lines changed: 1 addition & 44 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "sinbo"
3-
version = "1.2.0"
3+
version = "1.2.1"
44
edition = "2024"
55
description = "A CLI snippet manager. Store code once, retrieve it anywhere."
66
license = "MIT"
@@ -12,7 +12,6 @@ categories = ["command-line-utilities"]
1212
[dependencies]
1313
anyhow = "1.0.102"
1414
arboard = "3.6.1"
15-
atty = "0.2.14"
1615
clap = { version = "4.6.0", features = ["derive"] }
1716
colored = "3.1.1"
1817
dirs = "6.0.0"
@@ -25,4 +24,4 @@ rand = "0.8"
2524
rpassword = "7"
2625
zeroize = "1.8.2"
2726
clearscreen = "4.0.6"
28-
dialoguer = "0.12.0"
27+
dialoguer = "0.12.0"

assets/demo.gif

232 KB
Loading

assets/logo.af

20.4 KB
Binary file not shown.

readme.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@
1414

1515
---
1616

17+
## demo
18+
19+
![demo](assets/demo.gif)
20+
21+
1722
## Installation
1823

1924
**macOS / Linux**
@@ -139,7 +144,7 @@ sinbo search "deploy" -t infra # search within a tag
139144

140145
### `sinbo edit <n>`
141146

142-
Edit an existing snippet in `$EDITOR`. Preserves extension for syntax highlighting. Encrypted snippets cannot be edited — remove and re-add them.
147+
Edit an existing snippet in `$EDITOR`. Preserves extension for syntax highlighting. Encrypted snippets cannot be edited.
143148

144149
```bash
145150
sinbo edit rust-test

src/main.rs

Lines changed: 57 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use std::{
22
env, fs,
3-
io::{self, Read},
3+
io::{self, IsTerminal, Read},
44
process::Command,
55
};
66

@@ -48,6 +48,8 @@ enum Action {
4848
ext: Option<String>,
4949
#[arg(long, help = "Encrypt the snippet (prompted for password)")]
5050
encrypt: bool,
51+
#[arg(long, short, num_args = 1, help = "Add a description to metadata")]
52+
description: Option<String>,
5153
},
5254
#[command(about = "List all snippets", alias = "l")]
5355
List {
@@ -63,6 +65,8 @@ enum Action {
6365
name: String,
6466
#[arg(short, long, num_args = 1.., help = "Update tags")]
6567
tags: Option<Vec<String>>,
68+
#[arg(long, short, num_args = 1, help = "Add a description to metadata")]
69+
description: Option<String>,
6670
},
6771
#[command(about = "Search a query in snippets", alias = "s")]
6872
Search {
@@ -171,14 +175,15 @@ fn main() -> Result<()> {
171175
tags,
172176
ext,
173177
encrypt,
178+
description,
174179
} => {
175180
if storage.exists(&name) {
176181
return Err(anyhow!("snippet '{}' already exists", name));
177182
}
178183

179184
let content = if let Some(path) = file_name {
180185
fs::read_to_string(&path).with_context(|| format!("failed to read '{}'", path))?
181-
} else if atty::is(atty::Stream::Stdin) {
186+
} else if std::io::stdin().is_terminal() {
182187
open_editor(None, ext.as_deref(), encrypt)?
183188
} else {
184189
let mut buf = String::new();
@@ -193,14 +198,15 @@ fn main() -> Result<()> {
193198
}
194199

195200
let meta = SnippetMeta {
201+
description,
196202
modified_at: now_secs(),
197203
tags: tags.unwrap_or_default(),
198204
ext,
199205
};
200206

201-
if encrypt && !meta.tags.is_empty() {
207+
if encrypt && (!meta.tags.is_empty() || meta.description.is_some()) {
202208
eprintln!(
203-
"{} tags are stored in plaintext, avoid sensitive names",
209+
"{} tags and description are stored in plaintext, avoid sensitive names",
204210
"Warning:".yellow().bold()
205211
);
206212
}
@@ -232,13 +238,13 @@ fn main() -> Result<()> {
232238
}
233239

234240
eprintln!("{} {} snippets\n", "sinbo".cyan().bold(), snippets.len());
235-
236241
for s in &snippets {
237-
let tags_str = if s.meta.tags.is_empty() {
238-
String::new()
239-
} else {
240-
format!(" [{}]", s.meta.tags.join(", ").dimmed())
241-
};
242+
let ext_raw = s
243+
.meta
244+
.ext
245+
.as_deref()
246+
.map(|e| format!(" .{e}"))
247+
.unwrap_or_default();
242248

243249
let ext_str = s
244250
.meta
@@ -247,13 +253,44 @@ fn main() -> Result<()> {
247253
.map(|e| format!(" .{}", e.bright_black()))
248254
.unwrap_or_default();
249255

250-
let enc_str = if s.encrypted {
251-
format!(" {}", "Locked".yellow().dimmed())
256+
let desc_str = s.meta.description.clone().unwrap_or_default();
257+
258+
let tags_raw = if s.meta.tags.is_empty() {
259+
String::new()
252260
} else {
261+
format!("[{}]", s.meta.tags.join(", "))
262+
};
263+
264+
let tags_str = if s.meta.tags.is_empty() {
253265
String::new()
266+
} else {
267+
format!("[{}]", s.meta.tags.join(", ").dimmed())
268+
};
269+
270+
let name_ext_raw = format!("{}{}", s.name, ext_raw);
271+
let pad = 20usize.saturating_sub(name_ext_raw.len());
272+
273+
let tags_pad = 30usize.saturating_sub(tags_raw.len());
274+
275+
let end = if s.encrypted {
276+
format!(
277+
"{} --- {}",
278+
"Locked".yellow().dimmed(),
279+
desc_str.bright_black().italic()
280+
)
281+
} else {
282+
desc_str.bright_black().italic().to_string()
254283
};
255284

256-
println!("{}{}{}{}", s.name.cyan().bold(), tags_str, ext_str, enc_str);
285+
println!(
286+
"{}{}{}{}{}{}",
287+
s.name.cyan().bold(),
288+
ext_str,
289+
" ".repeat(pad),
290+
tags_str,
291+
" ".repeat(tags_pad),
292+
end
293+
);
257294

258295
if show {
259296
if s.encrypted {
@@ -270,7 +307,11 @@ fn main() -> Result<()> {
270307
storage.remove(&name)?;
271308
eprintln!("{} removed '{}'", "sinbo".cyan().bold(), name.yellow());
272309
}
273-
Action::Edit { name, tags } => {
310+
Action::Edit {
311+
name,
312+
tags,
313+
description,
314+
} => {
274315
let snippet = storage
275316
.get(&name)
276317
.with_context(|| format!("snippet '{}' not found", name))?;
@@ -282,7 +323,7 @@ fn main() -> Result<()> {
282323
));
283324
}
284325

285-
let content = if atty::is(atty::Stream::Stdin) {
326+
let content = if std::io::stdin().is_terminal() {
286327
open_editor(Some(&snippet.content), snippet.meta.ext.as_deref(), false)?
287328
} else {
288329
let mut buf = String::new();
@@ -297,6 +338,7 @@ fn main() -> Result<()> {
297338
}
298339

299340
let meta = SnippetMeta {
341+
description,
300342
modified_at: now_secs(),
301343
tags: tags.unwrap_or(snippet.meta.tags),
302344
ext: snippet.meta.ext,

src/storage.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use serde::{Deserialize, Serialize};
66

77
#[derive(Serialize, Deserialize)]
88
pub struct SnippetMeta {
9+
pub description: Option<String>,
910
pub tags: Vec<String>,
1011
pub ext: Option<String>,
1112
pub modified_at: u64,

0 commit comments

Comments
 (0)