Module: Jade::CLI::Q
- Defined in:
- lib/jade/cli/q.rb
Overview
Headless query interface to the same compiler intelligence the LSP server uses. Intended for tools and agents that want a quick JSON answer instead of speaking JSON-RPC.
Defined Under Namespace
Classes: Context
Constant Summary collapse
- USAGE =
<<~TXT.freeze Usage: jade q COMMAND [ARGS] hover FILE:LINE:COL Type info at the given position. symbols FILE Document symbols (outline) for FILE. defn FILE:LINE:COL Goto-definition location. refs FILE:LINE:COL Find all references (incl. declaration). api [MODULE|NAME] Stdlib signatures. No argument lists the modules; `Maybe` describes one; `List.map` picks a single symbol. find TERM Symbols whose name matches TERM. syntax [FORM] How a form is written (`lambda`, `case`, `interface`, …). No argument lists them all. FILE is relative to the project root (cwd). LINE and COL are 0-indexed (LSP convention). `api` and `find` cover the stdlib plus, inside a project, its own and its extensions' modules. `syntax` needs nothing at all. Everything else compiles the project, caching at .jade/cache so repeat queries are fast. TXT
Class Method Summary collapse
- .api(name) ⇒ Object
- .defn(arg) ⇒ Object
- .dump(result) ⇒ Object
- .find(term) ⇒ Object
- .hover(arg) ⇒ Object
- .listing(api) ⇒ Object
- .parse_position(arg) ⇒ Object
- .refs(arg) ⇒ Object
- .run(argv) ⇒ Object
- .skipped(api) ⇒ Object
- .symbols(file) ⇒ Object
- .syntax(form) ⇒ Object
Class Method Details
.api(name) ⇒ Object
52 53 54 55 56 57 58 59 |
# File 'lib/jade/cli/q.rb', line 52 def api(name) Api.load.then do |api| next listing(api) unless name (api.describe(name) || api.lookup(name)) .then { it || fail("no module or symbol named #{name}") } end end |
.defn(arg) ⇒ Object
104 105 106 107 108 109 110 111 |
# File 'lib/jade/cli/q.rb', line 104 def defn(arg) file, line, col = parse_position(arg) Context.new(file).then do |ctx| Jade::LSP::Converters.definition_for_path( ctx.path_at(line, col), ctx.registry, ctx.entry, ctx.source_root ) end end |
.dump(result) ⇒ Object
130 131 132 |
# File 'lib/jade/cli/q.rb', line 130 def dump(result) puts JSON.pretty_generate(result) end |
.find(term) ⇒ Object
61 62 63 64 65 66 67 |
# File 'lib/jade/cli/q.rb', line 61 def find(term) fail 'TERM required' unless term Api .load .then { { matches: it.search(term), **skipped(it) } } end |
.hover(arg) ⇒ Object
85 86 87 88 89 90 91 92 |
# File 'lib/jade/cli/q.rb', line 85 def hover(arg) file, line, col = parse_position(arg) Context.new(file).then do |ctx| Jade::LSP::Converters.hover_for_path( ctx.path_at(line, col), ctx.registry, ctx.entry ) end end |
.listing(api) ⇒ Object
77 78 79 |
# File 'lib/jade/cli/q.rb', line 77 def listing(api) { modules: api.modules, **skipped(api) } end |
.parse_position(arg) ⇒ Object
123 124 125 126 127 128 |
# File 'lib/jade/cli/q.rb', line 123 def parse_position(arg) fail 'FILE:LINE:COL required' unless arg fail "expected FILE:LINE:COL, got #{arg.inspect}" unless arg.count(':') == 2 arg.split(':').then { |(file, line, col)| [file, line.to_i, col.to_i] } end |
.refs(arg) ⇒ Object
113 114 115 116 117 118 119 120 121 |
# File 'lib/jade/cli/q.rb', line 113 def refs(arg) file, line, col = parse_position(arg) Context.new(file).then do |ctx| Jade::LSP::Converters.references_for_path( ctx.path_at(line, col), ctx.registry, ctx.entry, ctx.source_root, include_declaration: true, ) end end |
.run(argv) ⇒ Object
37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
# File 'lib/jade/cli/q.rb', line 37 def run(argv) case argv[0] when 'hover' then dump(hover(argv[1])) when 'symbols' then dump(symbols(argv[1])) when 'defn' then dump(defn(argv[1])) when 'refs' then dump(refs(argv[1])) when 'api' then dump(api(argv[1])) when 'find' then dump(find(argv[1])) when 'syntax' then dump(syntax(argv[1])) else warn USAGE exit 1 end end |
.skipped(api) ⇒ Object
81 82 83 |
# File 'lib/jade/cli/q.rb', line 81 def skipped(api) api.skipped.empty? ? {} : { skipped: api.skipped } end |
.symbols(file) ⇒ Object
94 95 96 97 98 99 100 101 102 |
# File 'lib/jade/cli/q.rb', line 94 def symbols(file) fail 'FILE required' unless file Context.new(file).entry.then do |entry| entry.ast.body.expressions.filter_map do |node| Jade::LSP::Converters.to_document_symbol(node, entry.source) end end end |