diff --git a/src/cmd.js b/src/cmd.js
index ca38072..3196f43 100644
--- a/src/cmd.js
+++ b/src/cmd.js
@@ -534,6 +534,13 @@ const change_html_file = (state, html_file) => {
return {...state, html_file}
}
+const goto_location = (state, loc) => {
+ return {
+ state: move_cursor(set_location(state, loc), loc.index),
+ effects: {type: 'set_focus'},
+ }
+}
+
const goto_definition = (state, index) => {
if(!state.parse_result.ok){
return {state, effects: {type: 'set_status', args: ['unresolved syntax errors']}}
@@ -569,12 +576,7 @@ const goto_definition = (state, index) => {
} else {
loc = {module: state.current_module, index: d.index}
}
- return {
- state: move_cursor(
- {...state, current_module: loc.module},
- loc.index,
- )
- }
+ return goto_location(state, loc)
}
}
}
@@ -950,6 +952,7 @@ export const COMMANDS = {
change_current_module,
change_entrypoint,
change_html_file,
+ goto_location,
goto_definition,
goto_problem,
move_cursor,
diff --git a/src/editor/calltree.js b/src/editor/calltree.js
index dd68f9d..ef60e75 100644
--- a/src/editor/calltree.js
+++ b/src/editor/calltree.js
@@ -1,19 +1,11 @@
import {exec} from '../index.js'
-import {el, stringify, fn_link, scrollIntoViewIfNeeded} from './domutils.js'
+import {el, scrollIntoViewIfNeeded, value_to_dom_el, join} from './domutils.js'
import {stringify_for_header} from '../value_explorer_utils.js'
import {find_node} from '../ast_utils.js'
import {with_version_number} from '../runtime/runtime.js'
import {is_expandable, root_calltree_node, get_deferred_calls, has_error}
from '../calltree.js'
-// TODO perf - quadratic difficulty
-const join = arr => arr.reduce(
- (acc, el) => acc.length == 0
- ? [el]
- : [...acc, ',', el],
- [],
-)
-
export class CallTree {
constructor(ui, container) {
this.ui = ui
@@ -111,11 +103,7 @@ export class CallTree {
...join(
// for arguments, use n.version_number - last version before call
with_version_number(this.state.rt_cxt, n.version_number, () =>
- n.args.map(
- a => typeof(a) == 'function'
- ? fn_link(a)
- : stringify_for_header(a)
- )
+ n.args.map(a => value_to_dom_el(a))
)
),
')' ,
@@ -124,7 +112,9 @@ export class CallTree {
// for return value, use n.last_version_number - last version that was
// created during call
with_version_number(this.state.rt_cxt, n.last_version_number, () =>
- (n.ok ? stringify_for_header(n.value) : stringify_for_header(n.error))
+ n.ok
+ ? value_to_dom_el(n.value)
+ : stringify_for_header(n.error)
)
),
),
diff --git a/src/editor/domutils.js b/src/editor/domutils.js
index 51ef427..a37b0ae 100644
--- a/src/editor/domutils.js
+++ b/src/editor/domutils.js
@@ -1,3 +1,6 @@
+import {exec} from '../index.js'
+import {stringify_for_header} from '../value_explorer_utils.js'
+
export function el(tag, className, ...children){
const result = document.createElement(tag)
if(typeof(className) == 'string'){
@@ -38,38 +41,40 @@ export function el(tag, className, ...children){
return result
}
-export function stringify(val){
- function fn_to_str(fn){
- // TODO if name is 'anonymous', then change name for code
- return fn.__location == null
- ? `${fn.name}`
- : `fn ${fn.name}`
- }
- if(typeof(val) == 'undefined') {
- return 'undefined'
- } else if(typeof(val) == 'function'){
- return fn_to_str(val)
- } else {
- return JSON.stringify(val, (key, value) => {
- if(typeof(value) == 'function'){
- return fn_to_str(value)
- } else {
- return value
- }
- })
- }
-}
-
-export function fn_link(fn){
- const str = stringify(fn)
+function fn_link(fn){
+ // TODO if name is empty or 'anonymous', then show its source code instead
+ // of name
+ const str = fn.__location == null
+ ? `${fn.name}`
+ : `fn ${fn.name}`
const c = document.createElement('div')
c.innerHTML = str
- return c.children[0]
+ const el = c.children[0]
+ if(fn.__location != null) {
+ el.addEventListener('click', e => {
+ e.stopPropagation()
+ exec('goto_location',fn.__location)
+ })
+ }
+ return el
}
+export function value_to_dom_el(value) {
+ return typeof(value) == 'function'
+ ? fn_link(value)
+ : stringify_for_header(value)
+}
+
+export function join(arr, separator = ', ') {
+ const result = []
+ for(let i = 0; i < arr.length; i++) {
+ result.push(arr[i])
+ if(i != arr.length - 1) {
+ result.push(separator)
+ }
+ }
+ return result
+}
// Idea is borrowed from:
diff --git a/src/editor/editor.js b/src/editor/editor.js
index 997e7b0..6a081ad 100644
--- a/src/editor/editor.js
+++ b/src/editor/editor.js
@@ -1,7 +1,7 @@
import {exec, get_state} from '../index.js'
import {ValueExplorer} from './value_explorer.js'
import {stringify_for_header} from '../value_explorer_utils.js'
-import {el, stringify, fn_link} from './domutils.js'
+import {el} from './domutils.js'
import {version_number_symbol} from '../calltree.js'
/*
diff --git a/src/editor/io_trace.js b/src/editor/io_trace.js
index d1a924e..f05d026 100644
--- a/src/editor/io_trace.js
+++ b/src/editor/io_trace.js
@@ -55,7 +55,6 @@ export class IO_Trace {
+ (is_used ? '' : 'native '),
item.name,
'(' ,
- // TODO fn_link, like in ./calltree.js
item.args.map(a => header(a)).join(', '),
'): ' ,
(item.ok ? stringify_for_header(item.value) : item.error.toString())
diff --git a/src/editor/logs.js b/src/editor/logs.js
index 6dd068a..db3c1f6 100644
--- a/src/editor/logs.js
+++ b/src/editor/logs.js
@@ -1,4 +1,4 @@
-import {el, scrollIntoViewIfNeeded} from './domutils.js'
+import {el, scrollIntoViewIfNeeded, value_to_dom_el, join} from './domutils.js'
import {exec} from '../index.js'
import {header} from '../value_explorer_utils.js'
import {with_version_number_of_log} from '../cmd.js'
@@ -72,10 +72,9 @@ export class Logs {
+ ':'
),
' ',
- with_version_number_of_log(state, log, () =>
- // TODO fn_link, for function args, like in ./calltree.js
- log.args.map(a => header(a)).join(', ')
- )
+ ...join(with_version_number_of_log(state, log, () =>
+ log.args.map(a => value_to_dom_el(a))
+ ))
)
)
}
diff --git a/src/editor/ui.js b/src/editor/ui.js
index 4c543ce..b1ae0cd 100644
--- a/src/editor/ui.js
+++ b/src/editor/ui.js
@@ -171,21 +171,6 @@ export class UI {
this.logs = new Logs(this, this.debugger.logs)
this.io_trace = new IO_Trace(this, this.debugger.io_trace)
- // TODO jump to another module
- // TODO use exec
- const jump_to_fn_location = (e) => {
- let loc
- if((loc = e.target.dataset.location) != null){
- loc = JSON.parse(loc)
- this.editor.set_cursor_position(loc.index)
- this.editor.focus()
- }
- }
-
- // TODO when click in calltree, do not jump to location, navigateCallTree
- // instead
- this.debugger.calltree.addEventListener('click', jump_to_fn_location)
-
this.render_current_module(state.current_module)
this.set_active_tab('calltree', true)
diff --git a/src/editor/value_explorer.js b/src/editor/value_explorer.js
index d41a21d..d186add 100644
--- a/src/editor/value_explorer.js
+++ b/src/editor/value_explorer.js
@@ -3,7 +3,7 @@
// TODO fns as clickable links (jump to definition), both for header and for
// content
-import {el, stringify, scrollIntoViewIfNeeded} from './domutils.js'
+import {el, scrollIntoViewIfNeeded} from './domutils.js'
import {with_code_execution} from '../index.js'
// TODO remove is_expandble, join with displayed entries
import {header, short_header, is_expandable, displayed_entries} from '../value_explorer_utils.js'