diff --git a/Public/js/views/debugger_highlighter.js b/Public/js/views/debugger_highlighter.js index 5c883c8..5eea6b8 100644 --- a/Public/js/views/debugger_highlighter.js +++ b/Public/js/views/debugger_highlighter.js @@ -21,35 +21,35 @@ export default class DebuggerHighlighter { for (const trace of traces) { const className = "debuggermatch"; - const location = Editor.calcRangePos( - this.editor, - trace.location.start, - trace.location.end - trace.location.start - ); - marks.push( - doc.markText(location.startPos, location.endPos, { - className: className, - }) - ); - - if (trace.location.start === trace.location.end) { + + if (trace.location.start !== trace.location.end) { + const location = Editor.calcRangePos( + this.editor, + trace.location.start, + trace.location.end - trace.location.start + ); + + marks.push( + doc.markText(location.startPos, location.endPos, { + className: className, + }) + ); + } else { const pos = doc.posFromIndex(trace.location.start); const widget = document.createElement("span"); widget.className = className; - widget.style.position = "absolute"; - widget.style.zIndex = "10"; - widget.style.height = `${defaultTextHeight * 1.5}px`; widget.style.width = "1px"; + widget.style.zIndex = "10"; + + this.editor.addWidget(pos, widget); const coords = editor.charCoords(pos, "local"); widget.style.left = `${coords.left}px`; widget.style.top = `${coords.top + 2}px`; - editor.getWrapperElement().appendChild(widget); - this.widgets.push(widget); } } @@ -60,17 +60,16 @@ export default class DebuggerHighlighter { const widget = document.createElement("span"); widget.className = "debuggerbacktrack"; - widget.style.position = "absolute"; - widget.style.zIndex = "10"; widget.style.height = `${defaultTextHeight * 1.5}px`; widget.style.width = `${editor.defaultCharWidth()}px`; + widget.style.zIndex = "10"; + + this.editor.addWidget(pos, widget); const coords = editor.charCoords(pos, "local"); widget.style.left = `${coords.left}px`; widget.style.top = `${coords.top + 2}px`; - editor.getWrapperElement().appendChild(widget); - this.widgets.push(widget); } }); @@ -85,7 +84,7 @@ export default class DebuggerHighlighter { marks.length = 0; for (const widget of this.widgets) { - widget.remove(); + widget.parentNode.removeChild(widget); } this.widgets.length = 0; }); diff --git a/Public/js/views/test_highlighter.js b/Public/js/views/test_highlighter.js index c332b04..a48accc 100644 --- a/Public/js/views/test_highlighter.js +++ b/Public/js/views/test_highlighter.js @@ -93,6 +93,7 @@ export default class TestHighlighter extends EventDispatcher { addLeftAnchor(location, attributes = {}) { const widget = document.createElement("span"); widget.className = "match-left"; + widget.style.height = `${this.textHeight * 1.5}px`; widget.style.width = "1px"; widget.style.zIndex = "10"; @@ -113,6 +114,7 @@ export default class TestHighlighter extends EventDispatcher { addRightAnchor(location, attributes = {}) { const widget = document.createElement("span"); widget.className = "match-right"; + widget.style.height = `${this.textHeight * 1.5}px`; widget.style.width = "1px"; widget.style.zIndex = "10"; diff --git a/Sources/App/Debugger/Context.swift b/Sources/App/Debugger/Context.swift index e436093..1130218 100644 --- a/Sources/App/Debugger/Context.swift +++ b/Sources/App/Debugger/Context.swift @@ -2,8 +2,6 @@ import Foundation extension Debugger { class Context { - static let shared = Context() - var instructions: [String] = [] var programCounter = 0 @@ -18,7 +16,7 @@ extension Debugger { var resets = 0 var backtracks = 0 - private init(stepCount: Int = 0, breakPoint: Int? = nil) { + init(stepCount: Int = 0, breakPoint: Int? = nil) { self.stepCount = stepCount self.breakPoint = breakPoint } diff --git a/Sources/App/Debugger/Debugger.swift b/Sources/App/Debugger/Debugger.swift index 84232c1..14aa967 100644 --- a/Sources/App/Debugger/Debugger.swift +++ b/Sources/App/Debugger/Debugger.swift @@ -3,7 +3,7 @@ import Foundation @testable @_spi(RegexBenchmark) import _StringProcessing struct Debugger { - func run(pattern: String, text: String, matchingOptions: [String] = []) throws { + func run(pattern: String, text: String, matchingOptions: [String] = [], context: Debugger.Context) throws { let ast = try _RegexParser.parse(pattern, .traditional) var sequence = [AST.MatchingOption]() @@ -32,7 +32,7 @@ struct Debugger { let program = try compile(ast, options: options) - Debugger.Context.shared.instructions = program.instructions.map { + context.instructions = program.instructions.map { $0.description } @@ -49,7 +49,8 @@ struct Debugger { do { _ = try Executor._firstMatch( program, - using: &cpu + using: &cpu, + context: context ) } catch {} } diff --git a/Sources/App/Debugger/Executor.swift b/Sources/App/Debugger/Executor.swift index 01b6145..ccb8d12 100644 --- a/Sources/App/Debugger/Executor.swift +++ b/Sources/App/Debugger/Executor.swift @@ -6,35 +6,42 @@ enum Executor { _ program: MEProgram, _ input: String, subjectBounds: Range, - searchBounds: Range + searchBounds: Range, + context: Debugger.Context ) throws -> Regex.Match? { try Executor._run( program, input, subjectBounds: subjectBounds, searchBounds: searchBounds, - mode: .partialFromFront) + mode: .partialFromFront, + context: context + ) } static func wholeMatch( _ program: MEProgram, _ input: String, subjectBounds: Range, - searchBounds: Range + searchBounds: Range, + context: Debugger.Context ) throws -> Regex.Match? { try Executor._run( program, input, subjectBounds: subjectBounds, searchBounds: searchBounds, - mode: .wholeString) + mode: .wholeString, + context: context + ) } static func firstMatch( _ program: MEProgram, _ input: String, subjectBounds: Range, - searchBounds: Range + searchBounds: Range, + context: Debugger.Context ) throws -> Regex.Match? { var cpu = Processor( program: program, @@ -45,19 +52,22 @@ enum Executor { ) return try Executor._firstMatch( program, - using: &cpu) + using: &cpu, + context: context + ) } static func _firstMatch( _ program: MEProgram, - using cpu: inout Processor + using cpu: inout Processor, + context: Debugger.Context ) throws -> Regex.Match? { let isGraphemeSemantic = program.initialOptions.semanticLevel == .graphemeCluster var low = cpu.searchBounds.lowerBound let high = cpu.searchBounds.upperBound while true { - if let m = try Executor._run(program, &cpu) { + if let m = try Executor._run(program, &cpu, context) { return m } // Fast-path for start-anchored regex @@ -84,7 +94,8 @@ extension Executor { _ input: String, subjectBounds: Range, searchBounds: Range, - mode: MatchMode + mode: MatchMode, + context: Debugger.Context ) throws -> Regex.Match? { var cpu = Processor( program: program, @@ -92,16 +103,17 @@ extension Executor { subjectBounds: subjectBounds, searchBounds: searchBounds, matchMode: mode) - return try _run(program, &cpu) + return try _run(program, &cpu, context) } static func _run( _ program: MEProgram, - _ cpu: inout Processor + _ cpu: inout Processor, + _ context: Debugger.Context ) throws -> Regex.Match? { let startPosition = cpu.currentPosition - Debugger.Context.shared.start = startPosition.utf16Offset(in: cpu.input) - guard let endIdx = try cpu.run() else { + context.start = startPosition.utf16Offset(in: cpu.input) + guard let endIdx = try cpu.run(context) else { return nil } let range = startPosition.. Input.Index? { + fileprivate mutating func run(_ context: Debugger.Context) throws -> Input.Index? { if self.state == .fail { if let e = failureReason { throw e @@ -122,7 +134,6 @@ extension Processor { } assert(isReset()) while true { - let context = Debugger.Context.shared context.programCounter = controller.pc.rawValue switch self.state { diff --git a/Sources/App/routes.swift b/Sources/App/routes.swift index 04aa61e..e9c545e 100644 --- a/Sources/App/routes.swift +++ b/Sources/App/routes.swift @@ -127,16 +127,16 @@ func routes(_ app: Application) throws { } func debug(pattern: String, text: String, matchOptions: [String], step: String?) throws -> ResultResponse { + let context = Debugger.Context() + func run(pattern: String, text: String, matchingOptions: [String] = [], until step: Int? = nil) throws { - let context = Debugger.Context.shared context.reset() context.breakPoint = step let debugger = Debugger() - try debugger.run(pattern: pattern, text: text, matchingOptions: matchingOptions) + try debugger.run(pattern: pattern, text: text, matchingOptions: matchingOptions, context: context) } - let context = Debugger.Context.shared let breakPoint: Int? if let step { breakPoint = Int(step)