Skip to content

Commit

Permalink
Allow specifying file start position
Browse files Browse the repository at this point in the history
Like helix-term/src/commands.rs:3426:15
  • Loading branch information
pickfire committed Jul 14, 2021
1 parent a4b077e commit b1cb72e
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 37 deletions.
33 changes: 17 additions & 16 deletions helix-term/src/application.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,13 @@ use helix_core::syntax;
use helix_lsp::{lsp, util::lsp_pos_to_pos, LspProgressMap};
use helix_view::{theme, Editor};

use crate::{args::Args, compositor::Compositor, config::Config, job::Jobs, ui};
use crate::{
args::{Args, Files},
compositor::Compositor,
config::Config,
job::Jobs,
ui,
};

use log::error;

Expand Down Expand Up @@ -77,24 +83,19 @@ impl Application {
let editor_view = Box::new(ui::EditorView::new(std::mem::take(&mut config.keys)));
compositor.push(editor_view);

if !args.files.is_empty() {
let first = &args.files[0]; // we know it's not empty
if first.is_dir() {
match args.files {
Files::Dir(d) => {
editor.new_file(Action::VerticalSplit);
compositor.push(Box::new(ui::file_picker(first.clone())));
} else {
for file 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, Action::VerticalSplit)?;
}
compositor.push(Box::new(ui::file_picker(d.clone())));
}
Files::Files(f) if f.is_empty() => {
editor.new_file(Action::VerticalSplit);
}
Files::Files(files) => {
for file in files {
editor.open(file, Action::VerticalSplit)?;
}
}
} else {
editor.new_file(Action::VerticalSplit);
}

editor.set_theme(theme);
Expand Down
57 changes: 53 additions & 4 deletions helix-term/src/args.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,24 @@
use anyhow::{Error, Result};
use helix_view::editor::File;
use std::path::PathBuf;

#[derive(Default)]
pub struct Args {
pub display_help: bool,
pub display_version: bool,
pub verbosity: u64,
pub files: Vec<PathBuf>,
pub files: Files,
}

pub enum Files {
Dir(PathBuf),
Files(Vec<File>),
}

impl Default for Files {
fn default() -> Files {
Files::Files(Vec::new())
}
}

impl Args {
Expand Down Expand Up @@ -39,15 +51,52 @@ impl Args {
}
}
}
arg => args.files.push(PathBuf::from(arg)),
arg => {
parse_files(arg, &mut args.files)?;
}
}
}

// push the remaining args, if any to the files
for filename in iter {
args.files.push(PathBuf::from(filename));
for arg in iter {
parse_files(arg, &mut args.files)?;
}

Ok(args)
}
}

/// Parse arg into [`File`] and add to files.
pub fn parse_files(s: &str, files: &mut Files) -> Result<()> {
let path = PathBuf::from(s);
if path.is_dir() {
match files {
Files::Dir(_) => return Err(Error::msg("only one dir is supported")),
Files::Files(f) if f.is_empty() => *files = Files::Dir(s.into()),
Files::Files(_) => return Err(Error::msg("cannot mix files with dir")),
}
} else {
match files {
Files::Dir(_) => return Err(Error::msg("cannot mix files with dir")),
Files::Files(ref mut files) => files.push(parse_file(s)),
}
}
Ok(())
}

/// Parse arg into [`File`].
pub(crate) fn parse_file(s: &str) -> File {
split_path_pos(s).unwrap_or_else(|| PathBuf::from(s).into())
}

/// Split file.rs:10:2 into [`File`].
///
/// Does not validate if file.rs is a file or directory.
fn split_path_pos(s: &str) -> Option<File> {
let mut s = s.rsplitn(3, ':');
let col: u32 = s.next()?.parse().ok()?;
let row: u32 = s.next()?.parse().ok()?;
let path = s.next()?.into();
let pos = Some((row.saturating_sub(1), col.saturating_sub(1)));
Some(File { path, pos })
}
13 changes: 8 additions & 5 deletions helix-term/src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ use insert::*;
use movement::Movement;

use crate::{
args,
compositor::{self, Component, Compositor},
ui::{self, Picker, Popup, Prompt, PromptEvent},
};
Expand Down Expand Up @@ -1198,7 +1199,7 @@ mod cmd {
_event: PromptEvent,
) -> anyhow::Result<()> {
let path = args.get(0).context("wrong argument count")?;
let _ = cx.editor.open(path.into(), Action::Replace)?;
let _ = cx.editor.open(args::parse_file(path), Action::Replace)?;
Ok(())
}

Expand Down Expand Up @@ -1961,7 +1962,7 @@ fn buffer_picker(cx: &mut Context) {
}
},
|editor: &mut Editor, (id, _path): &(DocumentId, Option<PathBuf>), _action| {
editor.switch(*id, Action::Replace);
editor.switch(*id, Action::Replace, None);
},
);
cx.push_layer(Box::new(picker));
Expand Down Expand Up @@ -2208,7 +2209,7 @@ fn push_jump(editor: &mut Editor) {
fn goto_last_accessed_file(cx: &mut Context) {
let alternate_file = view!(cx.editor).last_accessed_doc;
if let Some(alt) = alternate_file {
cx.editor.switch(alt, Action::Replace);
cx.editor.switch(alt, Action::Replace, None);
} else {
cx.editor.set_error("no last accessed buffer".to_owned())
}
Expand Down Expand Up @@ -2254,7 +2255,9 @@ fn goto_impl(
.uri
.to_file_path()
.expect("unable to convert URI to filepath");
let _id = editor.open(path, action).expect("editor.open failed");
let _id = editor
.open(path.into(), action)
.expect("editor.open failed");
let (view, doc) = current!(editor);
let definition_pos = location.range.start;
// TODO: convert inside server
Expand Down Expand Up @@ -3420,7 +3423,7 @@ fn split(cx: &mut Context, action: Action) {
let selection = doc.selection(view.id).clone();
let first_line = view.first_line;

cx.editor.switch(id, action);
cx.editor.switch(id, action, None);

// match the selection in the previous view
let (view, doc) = current!(cx.editor);
Expand Down
2 changes: 1 addition & 1 deletion helix-term/src/ui/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ pub fn file_picker(root: PathBuf) -> Picker<PathBuf> {
},
move |editor: &mut Editor, path: &PathBuf, action| {
editor
.open(path.into(), action)
.open(path.clone().into(), action)
.expect("editor.open failed");
},
)
Expand Down
47 changes: 36 additions & 11 deletions helix-view/src/editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,19 @@ pub use helix_core::register::Registers;
use helix_core::syntax;
use helix_core::Position;

/// File path with row and column.
#[derive(Debug, Default)]
pub struct File {
pub path: PathBuf,
pub pos: Option<(u32, u32)>,
}

impl From<PathBuf> for File {
fn from(path: PathBuf) -> File {
File { path, pos: None }
}
}

#[derive(Debug)]
pub struct Editor {
pub tree: Tree,
Expand Down Expand Up @@ -114,7 +127,7 @@ impl Editor {
}
}

pub fn switch(&mut self, id: DocumentId, action: Action) {
pub fn switch(&mut self, id: DocumentId, action: Action, pos: Option<(u32, u32)>) {
use crate::tree::Layout;
use helix_core::Selection;

Expand All @@ -140,10 +153,12 @@ impl Editor {
let (view, doc) = current!(self);

// initialize selection for view
let selection = doc
.selections
.entry(view.id)
.or_insert_with(|| Selection::point(0));
let pos = if let Some((row, col)) = pos {
Selection::point(doc.text().line_to_char(row as usize) + col as usize)
} else {
Selection::point(0)
};
let selection = doc.selections.entry(view.id).or_insert(pos);
// TODO: reuse align_view
let pos = selection.cursor();
let line = doc.text().char_to_line(pos);
Expand All @@ -156,14 +171,24 @@ impl Editor {
let view_id = self.tree.split(view, Layout::Horizontal);
// initialize selection for view
let doc = &mut self.documents[id];
doc.selections.insert(view_id, Selection::point(0));
if let Some((row, col)) = pos {
let pos = doc.text().line_to_char(row as usize) + col as usize;
doc.selections.insert(view_id, Selection::point(pos));
} else {
doc.selections.insert(view_id, Selection::point(0));
}
}
Action::VerticalSplit => {
let view = View::new(id);
let view_id = self.tree.split(view, Layout::Vertical);
// initialize selection for view
let doc = &mut self.documents[id];
doc.selections.insert(view_id, Selection::point(0));
if let Some((row, col)) = pos {
let pos = doc.text().line_to_char(row as usize) + col as usize;
doc.selections.insert(view_id, Selection::point(pos));
} else {
doc.selections.insert(view_id, Selection::point(0));
}
}
}

Expand All @@ -174,12 +199,12 @@ impl Editor {
let doc = Document::default();
let id = self.documents.insert(doc);
self.documents[id].id = id;
self.switch(id, action);
self.switch(id, action, None);
id
}

pub fn open(&mut self, path: PathBuf, action: Action) -> Result<DocumentId, Error> {
let path = crate::document::canonicalize_path(&path)?;
pub fn open(&mut self, file: File, action: Action) -> Result<DocumentId, Error> {
let path = crate::document::canonicalize_path(&file.path)?;

let id = self
.documents()
Expand Down Expand Up @@ -219,7 +244,7 @@ impl Editor {
id
};

self.switch(id, action);
self.switch(id, action, file.pos);
Ok(id)
}

Expand Down

0 comments on commit b1cb72e

Please sign in to comment.