From e3e2ba37320a5481471c43451d58875fd105d65f Mon Sep 17 00:00:00 2001 From: Jurjan-Paul Medema Date: Sun, 10 Dec 2023 13:57:57 +0100 Subject: [PATCH] scroll issue seems only 'solvable' by including tweaked version of parinfer-codemirror.js :-( --- index.html | 3 +- parinfer-codemirror.js | 663 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 665 insertions(+), 1 deletion(-) create mode 100755 parinfer-codemirror.js diff --git a/index.html b/index.html index d2bad77..fdfe00c 100644 --- a/index.html +++ b/index.html @@ -445,6 +445,7 @@ - + + diff --git a/parinfer-codemirror.js b/parinfer-codemirror.js new file mode 100755 index 0000000..5f1adc1 --- /dev/null +++ b/parinfer-codemirror.js @@ -0,0 +1,663 @@ +// +// Parinfer for CodeMirror 1.4.2 +// +// Copyright 2017 © Shaun Lebron +// MIT License +// + +//------------------------------------------------------------------------------ +// JS Module Boilerplate +// ('parinfer' is a dependency handled differently depending on environment) +//------------------------------------------------------------------------------ + +(function (root, factory) { + if (typeof define === 'function' && define.amd) { + define(['parinfer'], factory); + } + else if (typeof module === 'object' && module.exports) { + module.exports = factory(require('parinfer')); + } + else { + root.parinferCodeMirror = factory(root.parinfer); + } +}(this, function(parinfer) { // start module anonymous scope +"use strict"; + +//------------------------------------------------------------------------------ +// Constants +//------------------------------------------------------------------------------ + +// We attach our Parinfer state to this property on the CodeMirror instance. +var STATE_PROP = '__parinfer__'; + +var PAREN_MODE = 'paren'; +var INDENT_MODE = 'indent'; +var SMART_MODE = 'smart'; + +var MODES = [PAREN_MODE, INDENT_MODE, SMART_MODE]; + +var CLASSNAME_ERROR = 'parinfer-error'; +var CLASSNAME_PARENTRAIL = 'parinfer-paren-trail'; +var CLASSNAME_LOCUS_PAREN = 'parinfer-locus-paren'; + +var CLASSNAME_LOCUS_LAYER = 'parinfer-locus'; + +//------------------------------------------------------------------------------ +// State +// (`state` represents the parinfer state attached to a single CodeMirror editor) +//------------------------------------------------------------------------------ + +function initialState(cm, mode, options) { + return { + cm: cm, + mode: mode, + options: options, + enabled: false, + cursorTimeout: null, + monitorCursor: true, + prevCursorX: null, + prevCursorLine: null, + callbackCursor: null, + callbackChanges: null, + }; +} + +//------------------------------------------------------------------------------ +// Errors +//------------------------------------------------------------------------------ + +function error(msg) { + return 'parinferCodeMirror: ' + msg; +} + +function ensureMode(mode) { + if (MODES.indexOf(mode) === -1) { + throw error( + 'Mode "' + mode + '" is invalid. ' + + 'Must be one of: ' + MODES.join(',') + ); + } +} + +function ensureState(cm) { + var state = cm[STATE_PROP]; + if (!state) { + throw error( + 'You must call parinferCodeMirror.init(cm) on a CodeMirror instance ' + + 'before you can use the rest of the API.' + ); + } + return state; +} + +//------------------------------------------------------------------------------ +// Data conversion +//------------------------------------------------------------------------------ + +function convertChanges(changes) { + return changes.map(function(change) { + return { + x: change.from.ch, + lineNo: change.from.line, + oldText: change.removed.join('\n'), + newText: change.text.join('\n') + }; + }); +} + +//------------------------------------------------------------------------------ +// Markers +//------------------------------------------------------------------------------ + +function clearMarks(cm, className) { + var i; + var marks = cm.getAllMarks(); + for (i=0; i= stop.x) { + xs.pop(); + } + xs.push(stop.x); + xs.push(stop.x + (stop.ch === '(' ? 2 : 1)); + if (stop.argX != null) { + xs.push(stop.argX); + } + } + return xs; +} + +function nextStop(stops, x, dx) { + if (!stops) { + return null; + } + var i, stop, right, left; + for (i=0; i stop) { left = stop; } + } + if (dx === -1) { return left; } + if (dx === 1) { return right; } +} + +function getIndent(cm, lineNo) { + var line = cm.getLine(lineNo); + var i; + for (i=0; i 0) { + var spaces = Array(delta + 1).join(" "); + cm.replaceSelection(spaces); + } + else { + var x = cm.getCursor().ch; + cm.replaceRange("", {line: lineNo, ch: x+delta}, {line: lineNo, ch: x}, "+indent"); + } +} + +function indentAtCursor(cm, dx, stops) { + // Indent single line at cursor + var cursor = cm.getCursor(); + var lineNo = cursor.line; + var x = cursor.ch; + var indent = getIndent(cm, cursor.line); + + var stop = nextStop(stops, x, dx); + var useStops = (indent == null || x === indent); + var nextX = (stop != null && useStops) ? stop : Math.max(0, x+dx*2); + + if (indent != null && indent < x && x < nextX) { + var spaces = Array(nextX-x + 1).join(" "); + cm.replaceSelection(spaces); + } + else { + indentLine(cm, lineNo, nextX-x); + } +} + +function onTab(cm, dx) { + var hasSelection = cm.somethingSelected(); + var state = ensureState(cm); + var stops = expandTabStops(state.tabStops); + + if (hasSelection) { + indentSelection(cm, dx, stops); + } + else { + indentAtCursor(cm, dx, stops); + } +} + +//------------------------------------------------------------------------------ +// Locus/Guides layer +//------------------------------------------------------------------------------ + +function getLayerContainer(cm) { + var wrapper = cm.getWrapperElement(); + var lines = wrapper.querySelector('.CodeMirror-lines'); + var container = lines.parentNode; + return container; +} + +function parenSelected(paren, sel) { + return sel.contains({line: paren.lineNo, ch: paren.x}) !== -1; +} + +function pointRevealsParenTrail(trail, pos) { + return ( + pos.line === trail.lineNo && + trail.startX <= pos.ch /* && cursor.ch <= trail.endX */ + ); +} + +function hideParen(cm, paren) { + var sel = cm.getDoc().sel; + var sel0 = sel.ranges[0]; + var shouldShowCloser = ( + paren.lineNo === paren.closer.lineNo || + !paren.closer.trail || + pointRevealsParenTrail(paren.closer.trail, sel0.anchor) || + pointRevealsParenTrail(paren.closer.trail, sel0.head) || + parenSelected(paren.closer, sel) + ); + + if (!shouldShowCloser) { + addMark(cm, paren.closer.lineNo, paren.closer.x, paren.closer.x+1, CLASSNAME_LOCUS_PAREN); + } + hideParens(cm, paren.children); +} + +function hideParens(cm, parens) { + var i; + for (i=0; i maxWidth) { + maxWidth = line.length; + maxLineNo = i; + } + } + var wall = charPos(cm, {lineNo: maxLineNo, x: maxWidth}); + return wall.right; +} + +function addBox(cm, paren) { + var layer = cm[STATE_PROP].layer; + var paper = layer.paper; + var charW = layer.charW; + var charH = layer.charH; + + var open = charPos(cm, paren); + var close = charPos(cm, paren.closer); + + var r = 4; + + if (paren.closer.trail && paren.lineNo !== paren.closer.lineNo) { + switch (layer.type) { + case 'guides': + paper.path([ + 'M', open.midx, open.bottom, + 'V', close.bottom + ].join(' ')); + break; + case 'locus': + var right = getRightBound(cm, paren.lineNo, paren.closer.lineNo); + paper.path([ + 'M', open.midx, open.top+r, + 'A', r, r, 0, 0, 1, open.midx+r, open.top, + 'H', right-r, + 'A', r, r, 0, 0, 1, right, open.top+r, + 'V', close.bottom, + 'H', open.midx, + 'V', open.bottom + ].join(' ')); + break; + } + } + + addBoxes(cm, paren.children); +} + +function addBoxes(cm, parens) { + var i; + for (i=0; i