diff --git a/.vscode/launch.json b/.vscode/launch.json
new file mode 100644
index 0000000..dae727f
--- /dev/null
+++ b/.vscode/launch.json
@@ -0,0 +1,14 @@
+{
+ // Use IntelliSense to learn about possible attributes.
+ // Hover to view descriptions of existing attributes.
+ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
+ "version": "0.2.0",
+ "configurations": [
+
+ {
+ "type": "jdk",
+ "request": "launch",
+ "name": "Launch Java App"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/bundles/grammar/rex.xq b/bundles/grammar/rex.xq
index 1b88b7b..de45642 100644
--- a/bundles/grammar/rex.xq
+++ b/bundles/grammar/rex.xq
@@ -1,5 +1,5 @@
(: parse xq and save result:)
-import module namespace p="xq4" at "C:\Users\mrwhe\git\quodatum\basex-lsp\webapp\lsp\xq4.xqm";
+import module namespace p="xq4" at "C:\Users\mrwhe\git\quodatum\basex-lsp\webapp\lsp\ast\xq4.xqm";
declare variable $generator.xpath :="https://raw.githubusercontent.com/dnovatchev/Articles/refs/heads/main/Generators/Code/generator.xq";
declare variable $pdfbox-good.xqm :="../../test/sample.docs/pdfbox.xqm";
diff --git a/bundles/grammar/test-xquery.xq b/bundles/grammar/test-xquery.xq
index 137cd70..82071fc 100644
--- a/bundles/grammar/test-xquery.xq
+++ b/bundles/grammar/test-xquery.xq
@@ -1,3 +1,3 @@
-import module namespace p="xq4" at "C:\Users\mrwhe\git\quodatum\basex-lsp\webapp\lsp\xq4.xqm";
+import module namespace p="xq4" at "C:\Users\mrwhe\git\quodatum\basex-lsp\webapp\lsp\ast\xq4.xqm";
let $t:=fetch:text("https://raw.githubusercontent.com/dnovatchev/Articles/refs/heads/main/Generators/Code/generator.xq")=>lazy:cache()
return p:parse-Module($t)
\ No newline at end of file
diff --git a/webapp/lsp/ast/ast.xqm b/webapp/lsp/ast/ast.xqm
new file mode 100644
index 0000000..ac85a17
--- /dev/null
+++ b/webapp/lsp/ast/ast.xqm
@@ -0,0 +1,56 @@
+(: Abstract syntax tree
+@author Andy Bunce
+:)
+module namespace ast="lsp/ast";
+(: import module namespace p="xq4" at "xq4.xqm"; :)
+import module namespace xq4="java:quodatum.parser.xq4";
+
+(:~ build :)
+declare function ast:build($text as xs:string,$uri as xs:string:="")
+as element(*){
+ let $xml:= xq4:parseModule($text)=>prof:time("⏱️ p:parse-Module " || $uri)
+ return ($xml,
+ message(ast:report($xml),"REP"),
+ message(ast:report(ast:flatten($xml)),"flat")
+ )
+};
+
+(:~
+ :concrete to abstract: simplify by omitting elements with only one child
+:)
+declare function ast:flatten($input as element()) as element() {
+ if (1=count($input/*)) then ast:flatten($input/*)
+ else element {node-name($input) }
+ {$input/@*,
+ for $child in $input/node()
+ return
+ if ($child instance of element())
+ then ast:flatten($child)
+ else $child
+ }
+};
+
+(:-------------------------------------------:)
+
+declare function ast:report($el as element(*)) {
+
+ {count($el//element())}
+ {ast:max-node-depth($el)}
+
+};
+
+declare function ast:max-depth($nodes as node()*) as xs:integer {
+ if (empty($nodes)) then 0
+ else
+ max((
+ for $node in $nodes
+ return
+ if ($node instance of element())
+ then ast:max-depth($node/node()) + 1
+ else ast:max-depth($node/node())
+ ))
+};
+
+declare function ast:max-node-depth($root as node()) as xs:integer {
+ ast:max-depth($root)
+};
diff --git a/webapp/lsp/xq4.xqm b/webapp/lsp/ast/xq4.xqm
similarity index 100%
rename from webapp/lsp/xq4.xqm
rename to webapp/lsp/ast/xq4.xqm
diff --git a/webapp/lsp/docs.xqm b/webapp/lsp/docs.xqm
index 72f4c66..249f00d 100644
--- a/webapp/lsp/docs.xqm
+++ b/webapp/lsp/docs.xqm
@@ -4,11 +4,10 @@
@author Andy Bunce
:)
module namespace docs="lsp/docs";
-(: import module namespace p="xq4" at "xq4.xqm"; :)
-import module namespace xq4="java:quodatum.parser.xq4";
import module namespace pos="lsp/position" at "position.xqm";
import module namespace rpc = 'rpc' at 'jsonrpc.xqm';
import module namespace lsp-diags = 'lsp-diags' at 'providers/diagnostics.xqm';
+import module namespace ast = 'lsp/ast' at 'ast/ast.xqm';
(: save $textDocument data as session $socket properties
@return uri
@@ -119,7 +118,7 @@ declare function docs:parse(
)as map(*)?
{
let $text:=docs:get($socket,$file,"textDocument")?text
- let $xml:= xq4:parseModule($text)=>prof:time("⏱️ p:parse-Module " || $file)
+ let $xml:= ast:build($text, $file)
let $diags:=lsp-diags:list($file, $text, $xml)=>prof:time("⏱️ diags " || $file)
return (
ws:set($socket,docs:key($socket,$file,"parse"),$xml),
diff --git a/webapp/lsp/providers/documentSymbols.xqm b/webapp/lsp/providers/documentSymbols.xqm
index 4c136f4..7f48006 100644
--- a/webapp/lsp/providers/documentSymbols.xqm
+++ b/webapp/lsp/providers/documentSymbols.xqm
@@ -50,6 +50,7 @@ as hnd:Result{
declare function syms:FunctionDecl($parse as element(FunctionDecl),$state as hnd:Result )
as hnd:Result{
let $name:=syms:localName($parse/UnreservedFunctionEQName)
+ let $prev:=$state?result[$name eq ?name]
let $range:=lspt:Range(lspt:Position(0,0),lspt:Position(0,3))
let $sym:=lspt:DocumentSymbol($name,$lspt:SymbolKindMap('Method'),$range,$range,"FUN")
return ($state?result,$sym)=>hnd:Result(true())
diff --git a/webapp/static/clients/codemirror/grail.html b/webapp/static/clients/codemirror/grail.html
index bb83247..d24d46e 100644
--- a/webapp/static/clients/codemirror/grail.html
+++ b/webapp/static/clients/codemirror/grail.html
@@ -8,8 +8,8 @@
-
-
+
+
diff --git a/webapp/static/clients/codemirror/script.js b/webapp/static/clients/codemirror/script.js
index df30a57..089fa00 100644
--- a/webapp/static/clients/codemirror/script.js
+++ b/webapp/static/clients/codemirror/script.js
@@ -119,7 +119,8 @@ $("load").onchange = e => {
});
$("load").value = "";
};
-$("tConnect").addEventListener('quiet-change', event => {
+$("tConnect").addEventListener('quiet-change', e => {
+ e.preventDefault();
$("popConnect").showPopover()
});
$("msgIcon").onclick = e => {