|
| 1 | +# nu-version: 0.102.0 |
| 2 | + |
| 3 | +module lftp-completion-utils { |
| 4 | + def extract-host []: list<string> -> record<name: string, addr: string> { |
| 5 | + # Host is a list of lines, like: |
| 6 | + # ╭───┬──────────────────────────────╮ |
| 7 | + # │ 0 │ Host quanweb │ |
| 8 | + # │ 1 │ User quan │ |
| 9 | + # │ 2 │ Hostname quan.hoabinh.vn │ |
| 10 | + # │ 3 │ # ProxyJump farmb-omz │ |
| 11 | + # │ 4 │ │ |
| 12 | + # ╰───┴──────────────────────────────╯ |
| 13 | + let host = $in |
| 14 | + let $first_line = try { $host | first | str trim } catch { null } |
| 15 | + # Don't accept blocks like "Host *" |
| 16 | + if ($first_line | is-empty) or '*' in $first_line { |
| 17 | + null |
| 18 | + } else { |
| 19 | + let name = $first_line | split row -r '\s+' | get 1 |
| 20 | + # May not contain hostname |
| 21 | + match ($host | slice 1.. | find -ir '^\s*Hostname\s') { |
| 22 | + [] => null, |
| 23 | + $addr => { name: $name, addr: ($addr | str trim | split row -n 2 -r '\s+' | get 1) } |
| 24 | + } |
| 25 | + } |
| 26 | + } |
| 27 | + |
| 28 | + # Process a SSH config file |
| 29 | + export def process []: string -> record<hosts: list<record<name: string, addr: string>>, includes: list<string>> { |
| 30 | + let lines = $in | lines |
| 31 | + # Get 'Include' lines |
| 32 | + let include_lines = $lines | find -n -ir '^Include\s' | str trim | each { $in | split row -n 2 -r '\s+' | get 1 | str trim -c '"'} |
| 33 | + # Find "Host" blocks |
| 34 | + let marks = $lines | enumerate | find -n -ir '^Host\s' |
| 35 | + let mark_indices = $marks | get index | append ($lines | length) |
| 36 | + let hosts = $mark_indices | window 2 | each {|w| $lines | slice $w.0..<($w.1) } |
| 37 | + { |
| 38 | + hosts: ($hosts | each { $in | extract-host }), |
| 39 | + includes: $include_lines |
| 40 | + } |
| 41 | + } |
| 42 | + |
| 43 | + export def get-ssh-sites []: nothing -> table<value: string, description: string> { |
| 44 | + let files = [ |
| 45 | + '/etc/ssh/ssh_config', |
| 46 | + '~/.ssh/config' |
| 47 | + ] | filter {|file| $file | path exists } |
| 48 | + |
| 49 | + |
| 50 | + let first_result: record<hosts: list<record<name: string, addr: string>>, includes: list<string>> = $files | par-each {|file| |
| 51 | + let folder = $file | path expand | path dirname |
| 52 | + let r = $file | open --raw | process |
| 53 | + $r | update includes { each {|f| $folder | path join $f } } |
| 54 | + } | reduce {|it| merge deep $it --strategy=append } |
| 55 | + |
| 56 | + let $includes: list<string> = $first_result.includes | each {|f| |
| 57 | + if '*' in $f { |
| 58 | + glob $f |
| 59 | + } else if ($f | path exists) { |
| 60 | + [$f] |
| 61 | + } else [] |
| 62 | + } | flatten |
| 63 | + |
| 64 | + # Process include files |
| 65 | + let included_hosts: list<record<name: string, addr: string>> = (if ($includes | is-empty) { [] } else { |
| 66 | + let second_result = $includes | par-each {|p| $p | open --raw | process } | reduce {|it| merge deep $it --strategy=append } |
| 67 | + $second_result.hosts |
| 68 | + }) |
| 69 | + |
| 70 | + let hosts = $first_result.hosts ++ $included_hosts |
| 71 | + $hosts | each {|h| [$"sftp://($h.name)" $"fish://($h.name)"] | wrap value | insert description $h.addr } | flatten |
| 72 | + } |
| 73 | + |
| 74 | + export def get-bookmark-sites []: nothing -> table<value: string, description: string> { |
| 75 | + const FILE_PATH = '~/.local/share/lftp/bookmarks' | path expand |
| 76 | + let sites = open --raw $FILE_PATH | lines | split column -n 2 -r \s+ value description |
| 77 | + $sites | update value { $"bm:($in)" } |
| 78 | + } |
| 79 | +} |
| 80 | + |
| 81 | + |
| 82 | +def "nu-complete lftp-site" [] { |
| 83 | + use lftp-completion-utils get-ssh-sites |
| 84 | + use lftp-completion-utils get-bookmark-sites |
| 85 | + get-ssh-sites | append (get-bookmark-sites) |
| 86 | +} |
| 87 | + |
| 88 | +export extern 'lftp' [ |
| 89 | + -c: string # Execute the commands and exit |
| 90 | + -d # Switch on debugging mode |
| 91 | + -e: string # Execute the command just after selecting |
| 92 | + -p: int # Use the port for connection |
| 93 | + -u: string # Use the user/password for authentication |
| 94 | + --norc # Don't execute rc files from the home directory |
| 95 | + --help # Print the help and exit |
| 96 | + --version # Print lftp version and exit |
| 97 | + site?: string@"nu-complete lftp-site" # Host name, URL or bookmark name |
| 98 | +] |
0 commit comments