aboutsummaryrefslogtreecommitdiff
path: root/helix-term
diff options
context:
space:
mode:
Diffstat (limited to 'helix-term')
-rw-r--r--helix-term/src/application.rs23
-rw-r--r--helix-term/src/args.rs45
-rw-r--r--helix-term/src/commands.rs13
-rw-r--r--helix-term/src/main.rs2
4 files changed, 69 insertions, 14 deletions
diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs
index c376aefa..ae154a24 100644
--- a/helix-term/src/application.rs
+++ b/helix-term/src/application.rs
@@ -1,10 +1,14 @@
-use helix_core::{merge_toml_values, syntax};
+use helix_core::{merge_toml_values, pos_at_coords, syntax, Selection};
use helix_lsp::{lsp, util::lsp_pos_to_pos, LspProgressMap};
use helix_view::{theme, Editor};
use serde_json::json;
use crate::{
- args::Args, commands::apply_workspace_edit, compositor::Compositor, config::Config, job::Jobs,
+ args::Args,
+ commands::{align_view, apply_workspace_edit, Align},
+ compositor::Compositor,
+ config::Config,
+ job::Jobs,
ui,
};
@@ -130,7 +134,7 @@ impl Application {
// Unset path to prevent accidentally saving to the original tutor file.
doc_mut!(editor).set_path(None)?;
} else if !args.files.is_empty() {
- let first = &args.files[0]; // we know it's not empty
+ let first = &args.files[0].0; // we know it's not empty
if first.is_dir() {
std::env::set_current_dir(&first)?;
editor.new_file(Action::VerticalSplit);
@@ -138,16 +142,25 @@ impl Application {
} else {
let nr_of_files = args.files.len();
editor.open(first.to_path_buf(), Action::VerticalSplit)?;
- for file in args.files {
+ for (file, pos) in args.files {
if file.is_dir() {
return Err(anyhow::anyhow!(
"expected a path to file, found a directory. (to open a directory pass it as first argument)"
));
} else {
- editor.open(file.to_path_buf(), Action::Load)?;
+ let doc_id = editor.open(file, Action::Load)?;
+ // with Action::Load all documents have the same view
+ let view_id = editor.tree.focus;
+ let doc = editor.document_mut(doc_id).unwrap();
+ let pos = Selection::point(pos_at_coords(doc.text().slice(..), pos, true));
+ doc.set_selection(view_id, pos);
}
}
editor.set_status(format!("Loaded {} files.", nr_of_files));
+ // align the view to center after all files are loaded,
+ // does not affect views without pos since it is at the top
+ let (view, doc) = current!(editor);
+ align_view(doc, view, Align::Center);
}
} else if stdin().is_tty() {
editor.new_file(Action::VerticalSplit);
diff --git a/helix-term/src/args.rs b/helix-term/src/args.rs
index 40113db9..247d5b32 100644
--- a/helix-term/src/args.rs
+++ b/helix-term/src/args.rs
@@ -1,5 +1,6 @@
use anyhow::{Error, Result};
-use std::path::PathBuf;
+use helix_core::Position;
+use std::path::{Path, PathBuf};
#[derive(Default)]
pub struct Args {
@@ -7,7 +8,7 @@ pub struct Args {
pub display_version: bool,
pub load_tutor: bool,
pub verbosity: u64,
- pub files: Vec<PathBuf>,
+ pub files: Vec<(PathBuf, Position)>,
}
impl Args {
@@ -41,15 +42,49 @@ impl Args {
}
}
}
- arg => args.files.push(PathBuf::from(arg)),
+ arg => args.files.push(parse_file(arg)),
}
}
// push the remaining args, if any to the files
- for filename in iter {
- args.files.push(PathBuf::from(filename));
+ for arg in iter {
+ args.files.push(parse_file(arg));
}
Ok(args)
}
}
+
+/// Parse arg into [`PathBuf`] and position.
+pub(crate) fn parse_file(s: &str) -> (PathBuf, Position) {
+ let def = || (PathBuf::from(s), Position::default());
+ if Path::new(s).exists() {
+ return def();
+ }
+ split_path_row_col(s)
+ .or_else(|| split_path_row(s))
+ .unwrap_or_else(def)
+}
+
+/// Split file.rs:10:2 into [`PathBuf`], row and col.
+///
+/// Does not validate if file.rs is a file or directory.
+fn split_path_row_col(s: &str) -> Option<(PathBuf, Position)> {
+ let mut s = s.rsplitn(3, ':');
+ let col: usize = s.next()?.parse().ok()?;
+ let row: usize = s.next()?.parse().ok()?;
+ let path = s.next()?.into();
+ let pos = Position::new(row.saturating_sub(1), col.saturating_sub(1));
+ Some((path, pos))
+}
+
+/// Split file.rs:10 into [`PathBuf`] and row.
+///
+/// Does not validate if file.rs is a file or directory.
+fn split_path_row(s: &str) -> Option<(PathBuf, Position)> {
+ let (row, path) = s.rsplit_once(':')?;
+ let row: usize = row.parse().ok()?;
+ let path = path.into();
+ let pos = Position::new(row.saturating_sub(1), 0);
+ Some((path, pos))
+}
diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs
index 6123b7d2..fc0db6ed 100644
--- a/helix-term/src/commands.rs
+++ b/helix-term/src/commands.rs
@@ -37,6 +37,7 @@ use insert::*;
use movement::Movement;
use crate::{
+ args,
compositor::{self, Component, Compositor},
ui::{self, FilePicker, Picker, Popup, Prompt, PromptEvent},
};
@@ -113,13 +114,13 @@ impl<'a> Context<'a> {
}
}
-enum Align {
+pub(crate) enum Align {
Top,
Center,
Bottom,
}
-fn align_view(doc: &Document, view: &mut View, align: Align) {
+pub(crate) fn align_view(doc: &Document, view: &mut View, align: Align) {
let pos = doc
.selection(view.id)
.primary()
@@ -2028,7 +2029,13 @@ pub mod cmd {
) -> anyhow::Result<()> {
ensure!(!args.is_empty(), "wrong argument count");
for arg in args {
- let _ = cx.editor.open(arg.as_ref().into(), Action::Replace)?;
+ let (path, pos) = args::parse_file(arg);
+ let _ = cx.editor.open(path, Action::Replace)?;
+ let (view, doc) = current!(cx.editor);
+ let pos = Selection::point(pos_at_coords(doc.text().slice(..), pos, true));
+ doc.set_selection(view.id, pos);
+ // does not affect opening a buffer without pos
+ align_view(doc, view, Align::Center);
}
Ok(())
}
diff --git a/helix-term/src/main.rs b/helix-term/src/main.rs
index 88140130..0f504046 100644
--- a/helix-term/src/main.rs
+++ b/helix-term/src/main.rs
@@ -56,7 +56,7 @@ USAGE:
hx [FLAGS] [files]...
ARGS:
- <files>... Sets the input file to use
+ <files>... Sets the input file to use, position can also be specified via file[:row[:col]]
FLAGS:
-h, --help Prints help information