W60: Goto dialog parity — percent/offset/hex options
MC's goto dialog supports Line/Percent/Decimal offset/Hex offset modes. TLC's goto prompt previously only accepted line numbers. Parse the goto prompt input for multi-format support: - '50%' → goto 50% of the file (goto_percent) - '0x400' → goto byte offset 1024 (goto_offset, hex) - Number > line_count → treat as byte offset (goto_offset) - Number ≤ line_count → treat as line number (goto_line) Also updated the prompt label to 'Goto (line/50%/0x):' so the new formats are discoverable. Added 1 unit test verifying 50% goto lands near line 50 in a 100-line file. Tests: 1421 pass (was 1420), zero warnings.
This commit is contained in:
@@ -816,7 +816,7 @@ impl Viewer {
|
||||
let label = match self.prompt {
|
||||
Some(ViewerPrompt::Search) => " Search: ",
|
||||
Some(ViewerPrompt::SearchBackward) => " Search backward: ",
|
||||
Some(ViewerPrompt::GotoLine) => " Goto line: ",
|
||||
Some(ViewerPrompt::GotoLine) => " Goto (line/50%/0x): ",
|
||||
Some(ViewerPrompt::SaveBeforeQuit) => " Save before quit? (Y/N/Esc) ",
|
||||
None => return,
|
||||
};
|
||||
@@ -1202,13 +1202,42 @@ impl Viewer {
|
||||
}
|
||||
}
|
||||
ViewerPrompt::GotoLine => {
|
||||
if let Ok(n) = text.trim().parse::<u64>() {
|
||||
if n >= 1 {
|
||||
if let Ok(target) = self.goto_line(n) {
|
||||
let trimmed = text.trim();
|
||||
// Percent: "50%" → goto 50% of the file.
|
||||
if let Some(pct) = trimmed.strip_suffix('%') {
|
||||
if let Ok(n) = pct.parse::<u64>() {
|
||||
if n <= 100 {
|
||||
if let Ok(target) = self.goto_percent(n) {
|
||||
self.cursor = target.offset;
|
||||
self.top = target.line.saturating_sub(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Hex offset: "0x400" → goto byte offset 1024.
|
||||
} else if trimmed.starts_with("0x") || trimmed.starts_with("0X") {
|
||||
if let Ok(off) = u64::from_str_radix(&trimmed[2..], 16) {
|
||||
if let Ok(target) = self.goto_offset(off) {
|
||||
self.cursor = target.offset;
|
||||
self.top = target.line.saturating_sub(1);
|
||||
}
|
||||
}
|
||||
// Decimal offset: plain number → goto byte offset
|
||||
// if it's larger than the file's line count, else
|
||||
// goto line.
|
||||
} else if let Ok(n) = trimmed.parse::<u64>() {
|
||||
if n >= 1 {
|
||||
if n > self.goto.line_count() {
|
||||
if let Ok(target) = self.goto_offset(n) {
|
||||
self.cursor = target.offset;
|
||||
self.top = target.line.saturating_sub(1);
|
||||
}
|
||||
} else {
|
||||
if let Ok(target) = self.goto_line(n) {
|
||||
self.cursor = target.offset;
|
||||
self.top = target.line.saturating_sub(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ViewerPrompt::SaveBeforeQuit => {
|
||||
@@ -1849,6 +1878,21 @@ mod tests {
|
||||
assert!(!v.ruler);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn goto_accepts_percent_and_offset() {
|
||||
// Use a 100-line file so 50% = line 50.
|
||||
let lines: Vec<String> = (1..=100).map(|i| format!("line{i}")).collect();
|
||||
let content = lines.join("\n");
|
||||
let p = make_text("goto-fmt.txt", content.as_bytes());
|
||||
let mut v = Viewer::open(&p).unwrap();
|
||||
// Open goto prompt.
|
||||
v.prompt = Some(ViewerPrompt::GotoLine);
|
||||
v.prompt_input = "50%".to_string();
|
||||
// Activate the prompt — the commit handler processes it.
|
||||
v.handle_prompt_key(Key::ENTER);
|
||||
assert!(v.top >= 49 && v.top <= 51, "50% should land near line 50, got top={}", v.top);
|
||||
}
|
||||
|
||||
fn k(c: char) -> Key {
|
||||
Key { code: c as u32, mods: crate::key::Modifiers::empty() }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user