Skip to content

Commit

Permalink
Enable the Code Editor, with new apply-text-edits algo. (#9055)
Browse files Browse the repository at this point in the history
- Fix the UI problems with our CodeMirror integration (Fixed view stability; Fixed a focus bug; Fixed errors caused by diagnostics range exceptions; Fixed linter invalidation--see https://discuss.codemirror.net/t/problem-trying-to-force-linting/5823; Implemented edit-coalescing for performance).
- Introduce an algorithm for applying text edits to an AST. Compared to the GUI1 approach, the new algorithm supports deeper identity-stability for expressions (which is important for subexpression metadata and Y.Js sync), as well as reordered-subtree identification.
- Enable the code editor.
  • Loading branch information
kazcw authored Feb 19, 2024
1 parent d75523b commit c811a5a
Show file tree
Hide file tree
Showing 35 changed files with 1,831 additions and 534 deletions.
2 changes: 1 addition & 1 deletion app/gui2/mock/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ export function projectStore() {
const mod = projectStore.projectModel.createNewModule('Main.enso')
mod.doc.ydoc.emit('load', [])
const syncModule = new Ast.MutableModule(mod.doc.ydoc)
mod.transact(() => {
syncModule.transact(() => {
const root = Ast.parseBlock('main =\n', syncModule)
syncModule.replaceRoot(root)
})
Expand Down
22 changes: 22 additions & 0 deletions app/gui2/shared/ast/debug.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Ast } from './tree'

/// Returns a GraphViz graph illustrating parent/child relationships in the given subtree.
export function graphParentPointers(ast: Ast) {
const sanitize = (id: string) => id.replace('ast:', '').replace(/[^A-Za-z0-9]/g, '')
const parentToChild = new Array<{ parent: string; child: string }>()
const childToParent = new Array<{ child: string; parent: string }>()
ast.visitRecursiveAst((ast) => {
for (const child of ast.children()) {
if (child instanceof Ast)
parentToChild.push({ child: sanitize(child.id), parent: sanitize(ast.id) })
}
const parent = ast.parentId
if (parent) childToParent.push({ child: sanitize(ast.id), parent: sanitize(parent) })
})
let result = 'digraph parentPointers {\n'
for (const { parent, child } of parentToChild) result += `${parent} -> ${child};\n`
for (const { child, parent } of childToParent)
result += `${child} -> ${parent} [weight=0; color=red; style=dotted];\n`
result += '}\n'
return result
}
11 changes: 11 additions & 0 deletions app/gui2/shared/ast/ffi.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
import { createXXHash128 } from 'hash-wasm'
import init, { is_ident_or_operator, parse, parse_doc_to_json } from '../../rust-ffi/pkg/rust_ffi'
import { assertDefined } from '../util/assert'
import { isNode } from '../util/detect'

let xxHasher128: Awaited<ReturnType<typeof createXXHash128>> | undefined
export function xxHash128(input: string) {
assertDefined(xxHasher128, 'Module should have been loaded with `initializeFFI`.')
xxHasher128.init()
xxHasher128.update(input)
return xxHasher128.digest()
}

export async function initializeFFI(path?: string | undefined) {
if (isNode) {
const fs = await import('node:fs/promises')
Expand All @@ -9,6 +19,7 @@ export async function initializeFFI(path?: string | undefined) {
} else {
await init()
}
xxHasher128 = await createXXHash128()
}

// TODO[ao]: We cannot to that, because the ffi is used by cjs modules.
Expand Down
10 changes: 5 additions & 5 deletions app/gui2/shared/ast/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export function parentId(ast: Ast): AstId | undefined {
export function subtrees(module: Module, ids: Iterable<AstId>) {
const subtrees = new Set<AstId>()
for (const id of ids) {
let ast = module.get(id)
let ast = module.tryGet(id)
while (ast != null && !subtrees.has(ast.id)) {
subtrees.add(ast.id)
ast = ast.parent()
Expand All @@ -50,10 +50,10 @@ export function subtrees(module: Module, ids: Iterable<AstId>) {
}

/** Returns the IDs of the ASTs that are not descendants of any others in the given set. */
export function subtreeRoots(module: Module, ids: Set<AstId>) {
const roots = new Array<AstId>()
export function subtreeRoots(module: Module, ids: Set<AstId>): Set<AstId> {
const roots = new Set<AstId>()
for (const id of ids) {
const astInModule = module.get(id)
const astInModule = module.tryGet(id)
if (!astInModule) continue
let ast = astInModule.parent()
let hasParentInSet
Expand All @@ -64,7 +64,7 @@ export function subtreeRoots(module: Module, ids: Set<AstId>) {
}
ast = ast.parent()
}
if (!hasParentInSet) roots.push(id)
if (!hasParentInSet) roots.add(id)
}
return roots
}
Loading

0 comments on commit c811a5a

Please sign in to comment.