Compare commits
6 Commits
c484f2deb8
...
v1.1.6
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
829b6403b7 | ||
|
|
2d9b214ff4 | ||
|
|
80d2e7fd71 | ||
|
|
03e1311e90 | ||
|
|
a93f3ad9f6 | ||
|
|
b0407d6519 |
16
Cargo.lock
generated
16
Cargo.lock
generated
@@ -189,6 +189,7 @@ dependencies = [
|
|||||||
"crossterm_winapi",
|
"crossterm_winapi",
|
||||||
"derive_more",
|
"derive_more",
|
||||||
"document-features",
|
"document-features",
|
||||||
|
"filedescriptor",
|
||||||
"mio",
|
"mio",
|
||||||
"parking_lot",
|
"parking_lot",
|
||||||
"rustix",
|
"rustix",
|
||||||
@@ -1203,7 +1204,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ostiary"
|
name = "ostiary"
|
||||||
version = "1.1.2"
|
version = "1.1.6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"base64",
|
"base64",
|
||||||
@@ -1222,6 +1223,7 @@ dependencies = [
|
|||||||
"tokio",
|
"tokio",
|
||||||
"tokio-util",
|
"tokio-util",
|
||||||
"toml",
|
"toml",
|
||||||
|
"unicode-width 0.1.14",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1585,7 +1587,7 @@ dependencies = [
|
|||||||
"thiserror 2.0.18",
|
"thiserror 2.0.18",
|
||||||
"unicode-segmentation",
|
"unicode-segmentation",
|
||||||
"unicode-truncate",
|
"unicode-truncate",
|
||||||
"unicode-width",
|
"unicode-width 0.2.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1636,7 +1638,7 @@ dependencies = [
|
|||||||
"strum",
|
"strum",
|
||||||
"time",
|
"time",
|
||||||
"unicode-segmentation",
|
"unicode-segmentation",
|
||||||
"unicode-width",
|
"unicode-width 0.2.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2430,9 +2432,15 @@ checksum = "16b380a1238663e5f8a691f9039c73e1cdae598a30e9855f541d29b08b53e9a5"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"itertools",
|
"itertools",
|
||||||
"unicode-segmentation",
|
"unicode-segmentation",
|
||||||
"unicode-width",
|
"unicode-width 0.2.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-width"
|
||||||
|
version = "0.1.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-width"
|
name = "unicode-width"
|
||||||
version = "0.2.2"
|
version = "0.2.2"
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "ostiary"
|
name = "ostiary"
|
||||||
version = "1.1.2"
|
version = "1.1.6"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
crossterm = "0.29"
|
crossterm = { version = "0.29", features = ["use-dev-tty"] }
|
||||||
ratatui = "0.30"
|
ratatui = "0.30"
|
||||||
tokio = { version = "1", features = ["full"] }
|
tokio = { version = "1", features = ["full"] }
|
||||||
reqwest = { version = "0.12", features = ["json", "stream", "rustls-tls"], default-features = false }
|
reqwest = { version = "0.12", features = ["json", "stream", "rustls-tls"], default-features = false }
|
||||||
@@ -21,3 +21,4 @@ libc = "0.2"
|
|||||||
ed25519-dalek = { version = "2", features = ["rand_core"] }
|
ed25519-dalek = { version = "2", features = ["rand_core"] }
|
||||||
rand = "0.8"
|
rand = "0.8"
|
||||||
base64 = "0.22"
|
base64 = "0.22"
|
||||||
|
unicode-width = "0.1"
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ fi
|
|||||||
echo ""
|
echo ""
|
||||||
ok "Launching ${BINARY}..."
|
ok "Launching ${BINARY}..."
|
||||||
if { true </dev/tty; } 2>/dev/null; then
|
if { true </dev/tty; } 2>/dev/null; then
|
||||||
exec "$INSTALL_DIR/$BINARY" </dev/tty >/dev/tty 2>/dev/tty
|
"$INSTALL_DIR/$BINARY"
|
||||||
else
|
else
|
||||||
ok "Run: $BINARY"
|
ok "Run: $BINARY"
|
||||||
fi
|
fi
|
||||||
|
|||||||
14
src/main.rs
14
src/main.rs
@@ -172,17 +172,15 @@ async fn run_exec(
|
|||||||
fn prompt_first_endpoint() -> Result<(String, String)> {
|
fn prompt_first_endpoint() -> Result<(String, String)> {
|
||||||
use std::io::{BufRead, BufReader, Write};
|
use std::io::{BufRead, BufReader, Write};
|
||||||
|
|
||||||
// Open /dev/tty directly so input works even when launched via `curl | bash`
|
// Open /dev/tty read-only for keyboard input so the wizard works even when
|
||||||
// (where stdin is the pipe carrying the script, not the keyboard).
|
// stdin is a pipe (e.g. `curl | bash`). Writing goes through stdout so we
|
||||||
let tty = std::fs::OpenOptions::new()
|
// don't touch the terminal's write-side state before crossterm takes over.
|
||||||
.read(true)
|
let tty_in = std::fs::File::open("/dev/tty")
|
||||||
.write(true)
|
|
||||||
.open("/dev/tty")
|
|
||||||
.map_err(|e| anyhow::anyhow!(
|
.map_err(|e| anyhow::anyhow!(
|
||||||
"Не удалось открыть терминал ({e}). Запустите ostiary напрямую."
|
"Не удалось открыть терминал ({e}). Запустите ostiary напрямую."
|
||||||
))?;
|
))?;
|
||||||
let mut out = tty.try_clone()?;
|
let mut reader = BufReader::new(tty_in);
|
||||||
let mut reader = BufReader::new(tty);
|
let mut out = std::io::stdout();
|
||||||
|
|
||||||
writeln!(out)?;
|
writeln!(out)?;
|
||||||
writeln!(out, " ╔══════════════════════════════════╗")?;
|
writeln!(out, " ╔══════════════════════════════════╗")?;
|
||||||
|
|||||||
23
src/ui.rs
23
src/ui.rs
@@ -3,6 +3,7 @@ use crate::config::Config;
|
|||||||
use crate::executor;
|
use crate::executor;
|
||||||
use crate::app::{App, MessageLevel, Popup, UpdatingStatus};
|
use crate::app::{App, MessageLevel, Popup, UpdatingStatus};
|
||||||
use crate::text_input::TextInput;
|
use crate::text_input::TextInput;
|
||||||
|
use unicode_width::UnicodeWidthChar;
|
||||||
use ratatui::{
|
use ratatui::{
|
||||||
layout::{Alignment, Constraint, Direction, Layout, Rect},
|
layout::{Alignment, Constraint, Direction, Layout, Rect},
|
||||||
style::{Color, Modifier, Style},
|
style::{Color, Modifier, Style},
|
||||||
@@ -102,8 +103,11 @@ fn render_menu(f: &mut Frame, app: &mut App, area: Rect) {
|
|||||||
|
|
||||||
let endpoint_title = app.config.endpoints.iter()
|
let endpoint_title = app.config.endpoints.iter()
|
||||||
.find(|ep| ep.url == app.config.active_endpoint)
|
.find(|ep| ep.url == app.config.active_endpoint)
|
||||||
.map(|ep| format!(" {} ", ep.name))
|
.map(|ep| Line::from(vec![
|
||||||
.unwrap_or_else(|| " Меню ".to_string());
|
Span::raw(format!(" {} ", ep.name)),
|
||||||
|
Span::styled(" — [↹] Изменить ", Style::default().fg(Color::DarkGray)),
|
||||||
|
]))
|
||||||
|
.unwrap_or_else(|| Line::from(" Меню "));
|
||||||
|
|
||||||
let list = List::new(list_items).block(
|
let list = List::new(list_items).block(
|
||||||
Block::default()
|
Block::default()
|
||||||
@@ -542,10 +546,11 @@ fn render_popup(f: &mut Frame, popup: &mut Popup, config: &Config) {
|
|||||||
|
|
||||||
// Real terminal cursor in the active field
|
// Real terminal cursor in the active field
|
||||||
let af = *active_field;
|
let af = *active_field;
|
||||||
let cx = (chunks[af].x + 1 + fields[af].cursor as u16)
|
let cx = (chunks[af].x + 1 + display_cols(&fields[af].buf, fields[af].cursor))
|
||||||
.min(chunks[af].x + chunks[af].width.saturating_sub(2));
|
.min(chunks[af].x + chunks[af].width.saturating_sub(2));
|
||||||
f.set_cursor_position((cx, chunks[af].y + 1));
|
f.set_cursor_position((cx, chunks[af].y + 1));
|
||||||
|
|
||||||
|
|
||||||
let (title, hint) = if edit_index.is_some() {
|
let (title, hint) = if edit_index.is_some() {
|
||||||
(" Редактировать эндпоинт ", " Enter — далее / сохранить ")
|
(" Редактировать эндпоинт ", " Enter — далее / сохранить ")
|
||||||
} else {
|
} else {
|
||||||
@@ -655,7 +660,8 @@ fn render_command(
|
|||||||
),
|
),
|
||||||
area,
|
area,
|
||||||
);
|
);
|
||||||
let cursor_x = (area.x + 1 + input.cursor as u16).min(area.x + area.width.saturating_sub(2));
|
let col = if *secret { input.cursor as u16 } else { display_cols(&input.buf, input.cursor) };
|
||||||
|
let cursor_x = (area.x + 1 + col).min(area.x + area.width.saturating_sub(2));
|
||||||
f.set_cursor_position((cursor_x, area.y + 1));
|
f.set_cursor_position((cursor_x, area.y + 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -814,6 +820,15 @@ fn render_command(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Display-column width of `buf` up to char index `cursor`.
|
||||||
|
/// Accounts for wide characters (emoji, CJK) that occupy 2 terminal columns.
|
||||||
|
fn display_cols(buf: &str, cursor: usize) -> u16 {
|
||||||
|
buf.chars()
|
||||||
|
.take(cursor)
|
||||||
|
.map(|c| UnicodeWidthChar::width(c).unwrap_or(0))
|
||||||
|
.sum::<usize>() as u16
|
||||||
|
}
|
||||||
|
|
||||||
fn centered_rect(percent_x: u16, percent_y: u16, r: Rect) -> Rect {
|
fn centered_rect(percent_x: u16, percent_y: u16, r: Rect) -> Rect {
|
||||||
let popup_layout = Layout::default()
|
let popup_layout = Layout::default()
|
||||||
.direction(Direction::Vertical)
|
.direction(Direction::Vertical)
|
||||||
|
|||||||
Reference in New Issue
Block a user