Skip to content

Add path self command for getting absolute paths to files at parse time#14303

Merged
fdncred merged 7 commits intonushell:mainfrom
Bahex:const-path
Dec 6, 2024
Merged

Add path self command for getting absolute paths to files at parse time#14303
fdncred merged 7 commits intonushell:mainfrom
Bahex:const-path

Conversation

@Bahex
Copy link
Copy Markdown
Member

@Bahex Bahex commented Nov 11, 2024

Alternative solution to:

The other approach:

Description

Adds path const path self, a parse-time only command for getting the absolute path of the source file containing it, or any file relative to the source file.

  • Useful for any script or module that makes use of non nuscript files.
  • Removes the need for $env.CURRENT_FILE and $env.FILE_PWD.
  • Can be used in modules, sourced files or scripts.

Examples

# ~/.config/nushell/scripts/foo.nu
const paths = {
    self: (path self),
    dir: (path self .),
    sibling: (path self sibling),
    parent_dir: (path self ..),
    cousin: (path self ../cousin),
}

export def main [] {
    $paths
}
> use foo.nu
> foo
╭────────────┬────────────────────────────────────────────╮
 self        /home/user/.config/nushell/scripts/foo.nu  
 dir         /home/user/.config/nushell/scripts         
 sibling     /home/user/.config/nushell/scripts/sibling 
 parent_dir  /home/user/.config/nushell                 
 cousin      /home/user/.config/nushell/cousin          
╰────────────┴────────────────────────────────────────────╯

Trying to run in a non-const context

> path self
Error:   × this command can only run during parse-time
   ╭─[entry #1:1:1]
 1  path self 
   · ─────┬────
   ·      ╰── can't run after parse-time
   ╰────
  help: try assigning this command's output to a const variable

Trying to run in the REPL i.e. not in a file

> const foo = path self
Error:   × Error: nu::shell::file_not_found
   
     × File not found
      ╭─[entry #3:1:13]
    1  const foo = path self
      ·             ─────┬────
      ·                  ╰── Couldn't find current file
  │    ╰────

   ╭─[entry #3:1:13]
 1 │ const foo = path self
   ·             ─────┬────
   ·                  ╰── Encountered error during parse-time evaluation
   ╰────

Comparison with #14305

Pros

  • Self contained implementation, does not require changes in the parser.
  • More concise usage, especially with parent directories.

@sholderbach sholderbach added the A:const-eval Evaluation of const expressions at parse time if possible label Nov 11, 2024
@amtoine
Copy link
Copy Markdown
Member

amtoine commented Nov 20, 2024

an early review: following what's in #12195 sounds better and simpler to me than having a new command 😋

@devyn
Copy link
Copy Markdown
Contributor

devyn commented Nov 23, 2024

Yeah, I'm also not sure I like this just because the name is not very self-explanatory. If you're reading this and you don't know about it already you're probably not going to know what it does. Whereas $FILE_PWD | path join "foo.nu" seems very straightforward

@QORTEC
Copy link
Copy Markdown

QORTEC commented Nov 24, 2024

I would suggest renaming path const to path self, this makes purpose of the command more straightforward at a glance.

If we reuse the syntax of path join we get the following:

~> path self --help
Get a const of the current files path.

Optionally, append an additional path to the current files directory.

Usage:
  > path self ...(append) 

Flags:
  -h, --help: Display the help message for this command

Parameters:
  ...append <string>: Path to append to the current files directory.

Input/output types:
  ╭───┬──────────────┬──────────────╮
   # │    input     │    output    │
  ├───┼──────────────┼──────────────┤
   0  nothing       string       
  ╰───┴──────────────┴──────────────╯

Examples:
  Get the path of the current file
  > path self
  /home/scripts/foo.nu

  Get the directory of the current file
  > path self .
  /home/scripts

  Get the parent directory of the current file
  > path self ..
  /home

  Append a path to the current files directory
  > path self sibling
  /home/scripts/sibling

  From the current file go up one directory and append a path
  > path self .. cousin
  /home/../cousin

@Bahex
Copy link
Copy Markdown
Member Author

Bahex commented Nov 25, 2024

path self is a good suggestion, thanks!

@QORTEC
Copy link
Copy Markdown

QORTEC commented Nov 27, 2024

Trying to run in a non-const context

path const
Error:   × this command can only run during parse-time
   ╭─[entry #1:1:1]
 1  path const 
   · ─────┬────
   ·      ╰── can't run after parse-time
   ╰────
  help: try assigning this command's output to a const variable

I don't remember there being any nushell commands that are limited to a const context.
Does this limitation simplify the code?

@Bahex
Copy link
Copy Markdown
Member Author

Bahex commented Nov 28, 2024

Does this limitation simplify the code?

It simplifies things immensely, and let's path const to be implemented like any other command, without requiring any modifications to the parser or IR.

It can't run after parse-time, because it wouldn't be running within the context of the file.

@Bahex Bahex changed the title Add path const command for getting absolute paths to files at parse time Add path self command for getting absolute paths to files at parse time Dec 6, 2024
@Bahex
Copy link
Copy Markdown
Member Author

Bahex commented Dec 6, 2024

Renamed as suggested.

@Bahex Bahex marked this pull request as ready for review December 6, 2024 11:55
@fdncred
Copy link
Copy Markdown
Contributor

fdncred commented Dec 6, 2024

@Bahex I hope you don't mind. I added a couple tweaks. The TODO wasn't needed because that's checked with the input_output_types and just tweaks your examples and help.

@fdncred fdncred merged commit 8771872 into nushell:main Dec 6, 2024
@github-actions github-actions bot added this to the v0.101.0 milestone Dec 6, 2024
@fdncred
Copy link
Copy Markdown
Contributor

fdncred commented Dec 6, 2024

Thanks for working on this!

@fdncred
Copy link
Copy Markdown
Contributor

fdncred commented Dec 7, 2024

@Bahex I'm getting the error below when running nu --ide-check 100 /path/to/env.nu. This --ide-check parameter is used in the vscode extension to find errors.
image

When I put this in my env.nu or config.nu

const const_env = path self
print $"Hello, from ($const_env)!"

Am I just using it wrong or is this an edge case that is a new bug? Or maybe something needs to change in

nushell/src/ide.rs

Lines 75 to 138 in 9411458

pub fn check(engine_state: &mut EngineState, file_path: &str, max_errors: &Value) {
let cwd = std::env::current_dir().expect("Could not get current working directory.");
engine_state.add_env_var("PWD".into(), Value::test_string(cwd.to_string_lossy()));
engine_state.generate_nu_constant();
let mut working_set = StateWorkingSet::new(engine_state);
let file = std::fs::read(file_path);
let max_errors = if let Ok(max_errors) = max_errors.as_int() {
max_errors as usize
} else {
100
};
if let Ok(contents) = file {
let offset = working_set.next_span_start();
let block = parse(&mut working_set, Some(file_path), &contents, false);
for (idx, err) in working_set.parse_errors.iter().enumerate() {
if idx >= max_errors {
// eprintln!("Too many errors, stopping here. idx: {idx} max_errors: {max_errors}");
break;
}
let mut span = err.span();
span.start -= offset;
span.end -= offset;
let msg = err.to_string();
println!(
"{}",
json!({
"type": "diagnostic",
"severity": "Error",
"message": msg,
"span": {
"start": span.start,
"end": span.end
}
})
);
}
let flattened = flatten_block(&working_set, &block);
for flat in flattened {
if let FlatShape::VarDecl(var_id) = flat.1 {
let var = working_set.get_variable(var_id);
println!(
"{}",
json!({
"type": "hint",
"typename": var.ty.to_string(),
"position": {
"start": flat.0.start - offset,
"end": flat.0.end - offset
}
})
);
}
}
}
}

fdncred pushed a commit that referenced this pull request Dec 7, 2024
# Description

fixes
[this](#14303 (comment))
where lsp and ide integration would produce the following error

---

```sh
nu --ide-check 100 "/path/to/env.nu"
```
with
```nu
const const_env = path self
```
would lead to
```
Error: nu::shell::file_not_found

  × File not found
   ╭─[/path/to/env.nu:1:19]
 1 │ const const_env = path self
   ·                   ────┬────
   ·                       ╰── Couldn't find current file
   ╰────
```

# Tests + Formatting
- :green_circle: `cargo fmt --all`
- :green_circle: `cargo clippy --workspace`
@suimong
Copy link
Copy Markdown
Contributor

suimong commented Dec 7, 2024

Hey guys, really love this command, but just have a quick question about the semantics: I see that the returned path is expanded, ie if a nushell file is a symlink, path self will return the path to the source file rather than the symlink. While it is in line with $env.CURRENT_FILE, I'm just wondering what is the rationale that favors returning path expanded over as-is. To me there are use cases where getting the as-is path is desired (eg if the nushell script or module is installed by GNU stow), and I couldn't find an argument/use case against it. This is a genuine question and I'd really appreciate some clarification. Thanks in advance!

vyadh added a commit to vyadh/nutest that referenced this pull request Dec 7, 2024
@vyadh
Copy link
Copy Markdown
Contributor

vyadh commented Dec 7, 2024

This is super useful for nu-test as I needed it where $env.CURRENT_FILE wasn't defined (in a nu -c context). Thanks @Bahex

@Bahex
Copy link
Copy Markdown
Member Author

Bahex commented Dec 8, 2024

@suimong It's mostly because of how nushell resolves the paths to modules/files. For example

❯ ls -l | select name type target
╭─#─┬──name──┬──type───┬─target─╮
│ 0 │ bar.nu │ symlink │ foo.nu │
│ 1 │ foo.nu │ file    │        │
╰─#─┴──name──┴──type───┴─target─╯
❯ use bar.nu
❯ scope modules | select name file | where name in [foo bar]
╭─#─┬─name─┬────────────file────────────╮
│ 0 │ foo  │ /tmp/tmp.7r6aCwuV4y/foo.nu │
╰─#─┴─name─┴────────────file────────────╯

A possible workaround for your use case would be to have short files that set some constants and then source the file that contains the actual logic.

const ENTRY_POINT = (path self .)
source logic.nu
# logic.nu
# rather than using `path self` directly, use the pre-set constant variable
do-something $ENTRY_POINT

@suimong
Copy link
Copy Markdown
Contributor

suimong commented Dec 8, 2024

I see. @Bahex thanks for the explanation and the workaround. Still, having path find is a huge, huge empowerment for Nushell as a scripting language. Thanks again for making it happen!

@fdncred
Copy link
Copy Markdown
Contributor

fdncred commented Dec 9, 2024

path find?

@suimong
Copy link
Copy Markdown
Contributor

suimong commented Dec 9, 2024

path find?

Sorry I don't follow. We don't seem to have this command? Or is it a new command proposed in the spirit of path self?

@fdncred
Copy link
Copy Markdown
Contributor

fdncred commented Dec 9, 2024

You mention it above and I'm wondering the same thing, what is path find?

@suimong
Copy link
Copy Markdown
Contributor

suimong commented Dec 9, 2024

Ah, stupid me. I mean path self of course...

@Bahex Bahex deleted the const-path branch March 22, 2026 12:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A:const-eval Evaluation of const expressions at parse time if possible

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants