Implement `hx --tutor` and `:tutor` to load `tutor.txt` (#898)

* Implement `hx --tutor` and `:tutor` to load `tutor.txt`

* Document `hx --tutor` and `:tutor`

* Change `Document::set_path` to take an `Option`

* `Document::set_path` accepts an `Option<&Path>` instead of `&Path`.
* Remove `Editor::open_tutor` and make tutor-open functionality use
  `Editor::open` and `Document::set_path`.

* Use `PathBuf::join`

Co-authored-by: Ivan Tham <pickfire@riseup.net>

* Add comments explaining unsetting tutor path

Co-authored-by: Ivan Tham <pickfire@riseup.net>
pull/924/head
Omnikar 3 years ago committed by GitHub
parent 3b0c5e993a
commit e2ed691537
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -2,7 +2,7 @@
(Currently not fully documented, see the [keymappings](./keymap.md) list for more.) (Currently not fully documented, see the [keymappings](./keymap.md) list for more.)
See [tutor.txt](https://github.com/helix-editor/helix/blob/master/runtime/tutor.txt) for a vimtutor-like introduction. See [tutor.txt](https://github.com/helix-editor/helix/blob/master/runtime/tutor.txt) (accessible via `hx --tutor` or `:tutor`) for a vimtutor-like introduction.
## Registers ## Registers

@ -97,7 +97,12 @@ impl Application {
let editor_view = Box::new(ui::EditorView::new(std::mem::take(&mut config.keys))); let editor_view = Box::new(ui::EditorView::new(std::mem::take(&mut config.keys)));
compositor.push(editor_view); compositor.push(editor_view);
if !args.files.is_empty() { if args.load_tutor {
let path = helix_core::runtime_dir().join("tutor.txt");
editor.open(path, Action::VerticalSplit)?;
// 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]; // we know it's not empty
if first.is_dir() { if first.is_dir() {
std::env::set_current_dir(&first)?; std::env::set_current_dir(&first)?;

@ -5,6 +5,7 @@ use std::path::PathBuf;
pub struct Args { pub struct Args {
pub display_help: bool, pub display_help: bool,
pub display_version: bool, pub display_version: bool,
pub load_tutor: bool,
pub verbosity: u64, pub verbosity: u64,
pub files: Vec<PathBuf>, pub files: Vec<PathBuf>,
} }
@ -22,6 +23,7 @@ impl Args {
"--" => break, // stop parsing at this point treat the remaining as files "--" => break, // stop parsing at this point treat the remaining as files
"--version" => args.display_version = true, "--version" => args.display_version = true,
"--help" => args.display_help = true, "--help" => args.display_help = true,
"--tutor" => args.load_tutor = true,
arg if arg.starts_with("--") => { arg if arg.starts_with("--") => {
return Err(Error::msg(format!( return Err(Error::msg(format!(
"unexpected double dash argument: {}", "unexpected double dash argument: {}",

@ -1557,7 +1557,8 @@ mod cmd {
let (_, doc) = current!(cx.editor); let (_, doc) = current!(cx.editor);
if let Some(path) = path { if let Some(path) = path {
doc.set_path(path.as_ref()).context("invalid filepath")?; doc.set_path(Some(path.as_ref()))
.context("invalid filepath")?;
} }
if doc.path().is_none() { if doc.path().is_none() {
bail!("cannot write a buffer without a filename"); bail!("cannot write a buffer without a filename");
@ -2099,6 +2100,18 @@ mod cmd {
Ok(()) Ok(())
} }
fn tutor(
cx: &mut compositor::Context,
_args: &[&str],
_event: PromptEvent,
) -> anyhow::Result<()> {
let path = helix_core::runtime_dir().join("tutor.txt");
cx.editor.open(path, Action::Replace)?;
// Unset path to prevent accidentally saving to the original tutor file.
doc_mut!(cx.editor).set_path(None)?;
Ok(())
}
pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[
TypableCommand { TypableCommand {
name: "quit", name: "quit",
@ -2351,7 +2364,14 @@ mod cmd {
doc: "Open the file in a horizontal split.", doc: "Open the file in a horizontal split.",
fun: hsplit, fun: hsplit,
completer: Some(completers::filename), completer: Some(completers::filename),
} },
TypableCommand {
name: "tutor",
aliases: &[],
doc: "Open the tutorial.",
fun: tutor,
completer: None,
},
]; ];
pub static COMMANDS: Lazy<HashMap<&'static str, &'static TypableCommand>> = Lazy::new(|| { pub static COMMANDS: Lazy<HashMap<&'static str, &'static TypableCommand>> = Lazy::new(|| {

@ -368,7 +368,7 @@ impl Document {
let mut doc = Self::from(rope, Some(encoding)); let mut doc = Self::from(rope, Some(encoding));
// set the path and try detecting the language // set the path and try detecting the language
doc.set_path(path)?; doc.set_path(Some(path))?;
if let Some(loader) = config_loader { if let Some(loader) = config_loader {
doc.detect_language(theme, loader); doc.detect_language(theme, loader);
} }
@ -553,12 +553,16 @@ impl Document {
self.encoding self.encoding
} }
pub fn set_path(&mut self, path: &Path) -> Result<(), std::io::Error> { pub fn set_path(&mut self, path: Option<&Path>) -> Result<(), std::io::Error> {
let path = helix_core::path::get_canonicalized_path(path)?; let path = if let Some(p) = path {
Some(helix_core::path::get_canonicalized_path(p)?)
} else {
path.map(|p| p.into())
};
// if parent doesn't exist we still want to open the document // if parent doesn't exist we still want to open the document
// and error out when document is saved // and error out when document is saved
self.path = Some(path); self.path = path;
Ok(()) Ok(())
} }

Loading…
Cancel
Save