A Wikiful of Hacks: Hacks.Wiki is an experiment to organise quick hacks, notes, bookmarks and tools into an easy-to-build-and-maintain “Digital Garden”.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

1 lines
28 KiB

import{showPanel,EditorView,getPanel,Decoration,ViewPlugin,runScopeHandlers}from"@codemirror/view";import{codePointAt,fromCodePoint,codePointSize,StateEffect,StateField,EditorSelection,Facet,combineConfig,CharCategory,RangeSetBuilder,Prec,EditorState,findClusterBreak}from"@codemirror/state";import elt from"crelt";const basicNormalize=typeof String.prototype.normalize=="function"?x=>x.normalize("NFKD"):x=>x;class SearchCursor{constructor(text,query,from=0,to=text.length,normalize,test){this.test=test;this.value={from:0,to:0};this.done=false;this.matches=[];this.buffer="";this.bufferPos=0;this.iter=text.iterRange(from,to);this.bufferStart=from;this.normalize=normalize?x=>normalize(basicNormalize(x)):basicNormalize;this.query=this.normalize(query)}peek(){if(this.bufferPos==this.buffer.length){this.bufferStart+=this.buffer.length;this.iter.next();if(this.iter.done)return-1;this.bufferPos=0;this.buffer=this.iter.value}return codePointAt(this.buffer,this.bufferPos)}next(){while(this.matches.length)this.matches.pop();return this.nextOverlapping()}nextOverlapping(){for(;;){let next=this.peek();if(next<0){this.done=true;return this}let str=fromCodePoint(next),start=this.bufferStart+this.bufferPos;this.bufferPos+=codePointSize(next);let norm=this.normalize(str);for(let i=0,pos=start;;i++){let code=norm.charCodeAt(i);let match=this.match(code,pos);if(match){this.value=match;return this}if(i==norm.length-1)break;if(pos==start&&i<str.length&&str.charCodeAt(i)==code)pos++}}}match(code,pos){let match=null;for(let i=0;i<this.matches.length;i+=2){let index=this.matches[i],keep=false;if(this.query.charCodeAt(index)==code){if(index==this.query.length-1){match={from:this.matches[i+1],to:pos+1}}else{this.matches[i]++;keep=true}}if(!keep){this.matches.splice(i,2);i-=2}}if(this.query.charCodeAt(0)==code){if(this.query.length==1)match={from:pos,to:pos+1};else this.matches.push(1,pos)}if(match&&this.test&&!this.test(match.from,match.to,this.buffer,this.bufferPos))match=null;return match}}if(typeof Symbol!="undefined")SearchCursor.prototype[Symbol.iterator]=function(){return this};const empty={from:-1,to:-1,match:/.*/.exec("")};const baseFlags="gm"+(/x/.unicode==null?"":"u");class RegExpCursor{constructor(text,query,options,from=0,to=text.length){this.text=text;this.to=to;this.curLine="";this.done=false;this.value=empty;if(/\\[sWDnr]|\n|\r|\[\^/.test(query))return new MultilineRegExpCursor(text,query,options,from,to);this.re=new RegExp(query,baseFlags+((options===null||options===void 0?void 0:options.ignoreCase)?"i":""));this.test=options===null||options===void 0?void 0:options.test;this.iter=text.iter();let startLine=text.lineAt(from);this.curLineStart=startLine.from;this.matchPos=toCharEnd(text,from);this.getLine(this.curLineStart)}getLine(skip){this.iter.next(skip);if(this.iter.lineBreak){this.curLine=""}else{this.curLine=this.iter.value;if(this.curLineStart+this.curLine.length>this.to)this.curLine=this.curLine.slice(0,this.to-this.curLineStart);this.iter.next()}}nextLine(){this.curLineStart=this.curLineStart+this.curLine.length+1;if(this.curLineStart>this.to)this.curLine="";else this.getLine(0)}next(){for(let off=this.matchPos-this.curLineStart;;){this.re.lastIndex=off;let match=this.matchPos<=this.to&&this.re.exec(this.curLine);if(match){let from=this.curLineStart+match.index,to=from+match[0].length;this.matchPos=toCharEnd(this.text,to+(from==to?1:0));if(from==this.curLineStart+this.curLine.length)this.nextLine();if((from<to||from>this.value.to)&&(!this.test||this.test(from,to,match))){this.value={from:from,to:to,match:match};return this}off=this.matchPos-this.curLineStart}else if(this.curLineStart+this.curLine.length<this.to){this.nextLine();off=0}else{this.done=true;return this}}}}const flattened=new WeakMap;class FlattenedDoc{constructor(from,text){this.from=from;this.text=text}get to(){return this.from+this.text.length}static get(doc,from,to){let cached=flattened.get(doc);if(!cached||cached.from>=to||cached.to<=from){let flat=new FlattenedDoc(from,doc.sliceString(from,to));flattened.set(doc,flat);return flat}if(cached.from==from&&cached.to==to)return cached;let{text,from:cachedFrom}=cached;if(cachedFrom>from){text=doc.sliceString(from,cachedFrom)+text;cachedFrom=from}if(cached.to<to)text+=doc.sliceString(cached.to,to);flattened.set(doc,new FlattenedDoc(cachedFrom,text));return new FlattenedDoc(from,text.slice(from-cachedFrom,to-cachedFrom))}}class MultilineRegExpCursor{constructor(text,query,options,from,to){this.text=text;this.to=to;this.done=false;this.value=empty;this.matchPos=toCharEnd(text,from);this.re=new RegExp(query,baseFlags+((options===null||options===void 0?void 0:options.ignoreCase)?"i":""));this.test=options===null||options===void 0?void 0:options.test;this.flat=FlattenedDoc.get(text,from,this.chunkEnd(from+5e3))}chunkEnd(pos){return pos>=this.to?this.to:this.text.lineAt(pos).to}next(){for(;;){let off=this.re.lastIndex=this.matchPos-this.flat.from;let match=this.re.exec(this.flat.text);if(match&&!match[0]&&match.index==off){this.re.lastIndex=off+1;match=this.re.exec(this.flat.text)}if(match){let from=this.flat.from+match.index,to=from+match[0].length;if((this.flat.to>=this.to||match.index+match[0].length<=this.flat.text.length-10)&&(!this.test||this.test(from,to,match))){this.value={from:from,to:to,match:match};this.matchPos=toCharEnd(this.text,to+(from==to?1:0));return this}}if(this.flat.to==this.to){this.done=true;return this}this.flat=FlattenedDoc.get(this.text,this.flat.from,this.chunkEnd(this.flat.from+this.flat.text.length*2))}}}if(typeof Symbol!="undefined"){RegExpCursor.prototype[Symbol.iterator]=MultilineRegExpCursor.prototype[Symbol.iterator]=function(){return this}}function validRegExp(source){try{new RegExp(source,baseFlags);return true}catch(_a){return false}}function toCharEnd(text,pos){if(pos>=text.length)return pos;let line=text.lineAt(pos),next;while(pos<line.to&&(next=line.text.charCodeAt(pos-line.from))>=56320&&next<57344)pos++;return pos}function createLineDialog(view){let input=elt("input",{class:"cm-textfield",name:"line"});let dom=elt("form",{class:"cm-gotoLine",onkeydown:event=>{if(event.keyCode==27){event.preventDefault();view.dispatch({effects:dialogEffect.of(false)});view.focus()}else if(event.keyCode==13){event.preventDefault();go()}},onsubmit:event=>{event.preventDefault();go()}},elt("label",view.state.phrase("Go to line"),": ",input)," ",elt("button",{class:"cm-button",type:"submit"},view.state.phrase("go")));function go(){let match=/^([+-])?(\d+)?(:\d+)?(%)?$/.exec(input.value);if(!match)return;let{state}=view,startLine=state.doc.lineAt(state.selection.main.head);let[,sign,ln,cl,percent]=match;let col=cl?+cl.slice(1):0;let line=ln?+ln:startLine.number;if(ln&&percent){let pc=line/100;if(sign)pc=pc*(sign=="-"?-1:1)+startLine.number/state.doc.lines;line=Math.round(state.doc.lines*pc)}else if(ln&&sign){line=line*(sign=="-"?-1:1)+startLine.number}let docLine=state.doc.line(Math.max(1,Math.min(state.doc.lines,line)));view.dispatch({effects:dialogEffect.of(false),selection:EditorSelection.cursor(docLine.from+Math.max(0,Math.min(col,docLine.length))),scrollIntoView:true});view.focus()}return{dom:dom}}const dialogEffect=StateEffect.define();const dialogField=StateField.define({create(){return true},update(value,tr){for(let e of tr.effects)if(e.is(dialogEffect))value=e.value;return value},provide:f=>showPanel.from(f,val=>val?createLineDialog:null)});const gotoLine=view=>{let panel=getPanel(view,createLineDialog);if(!panel){let effects=[dialogEffect.of(true)];if(view.state.field(dialogField,false)==null)effects.push(StateEffect.appendConfig.of([dialogField,baseTheme$1]));view.dispatch({effects:effects});panel=getPanel(view,createLineDialog)}if(panel)panel.dom.querySelector("input").focus();return true};const baseTheme$1=EditorView.baseTheme({".cm-panel.cm-gotoLine":{padding:"2px 6px 4px","& label":{fontSize:"80%"}}});const defaultHighlightOptions={highlightWordAroundCursor:false,minSelectionLength:1,maxMatches:100,wholeWords:false};const highlightConfig=Facet.define({combine(options){return combineConfig(options,defaultHighlightOptions,{highlightWordAroundCursor:(a,b)=>a||b,minSelectionLength:Math.min,maxMatches:Math.min})}});function highlightSelectionMatches(options){let ext=[defaultTheme,matchHighlighter];if(options)ext.push(highlightConfig.of(options));return ext}const matchDeco=Decoration.mark({class:"cm-selectionMatch"});const mainMatchDeco=Decoration.mark({class:"cm-selectionMatch cm-selectionMatch-main"});function insideWordBoundaries(check,state,from,to){return(from==0||check(state.sliceDoc(from-1,from))!=CharCategory.Word)&&(to==state.doc.length||check(state.sliceDoc(to,to+1))!=CharCategory.Word)}function insideWord(check,state,from,to){return check(state.sliceDoc(from,from+1))==CharCategory.Word&&check(state.sliceDoc(to-1,to))==CharCategory.Word}const matchHighlighter=ViewPlugin.fromClass(class{constructor(view){this.decorations=this.getDeco(view)}update(update){if(update.selectionSet||update.docChanged||update.viewportChanged)this.decorations=this.getDeco(update.view)}getDeco(view){let conf=view.state.facet(highlightConfig);let{state}=view,sel=state.selection;if(sel.ranges.length>1)return Decoration.none;let range=sel.main,query,check=null;if(range.empty){if(!conf.highlightWordAroundCursor)return Decoration.none;let word=state.wordAt(range.head);if(!word)return Decoration.none;check=state.charCategorizer(range.head);query=state.sliceDoc(word.from,word.to)}else{let len=range.to-range.from;if(len<conf.minSelectionLength||len>200)return Decoration.none;if(conf.wholeWords){query=state.sliceDoc(range.from,range.to);check=state.charCategorizer(range.head);if(!(insideWordBoundaries(check,state,range.from,range.to)&&insideWord(check,state,range.from,range.to)))return Decoration.none}else{query=state.sliceDoc(range.from,range.to).trim();if(!query)return Decoration.none}}let deco=[];for(let part of view.visibleRanges){let cursor=new SearchCursor(state.doc,query,part.from,part.to);while(!cursor.next().done){let{from,to}=cursor.value;if(!check||insideWordBoundaries(check,state,from,to)){if(range.empty&&from<=range.from&&to>=range.to)deco.push(mainMatchDeco.range(from,to));else if(from>=range.to||to<=range.from)deco.push(matchDeco.range(from,to));if(deco.length>conf.maxMatches)return Decoration.none}}}return Decoration.set(deco)}},{decorations:v=>v.decorations});const defaultTheme=EditorView.baseTheme({".cm-selectionMatch":{backgroundColor:"#99ff7780"},".cm-searchMatch .cm-selectionMatch":{backgroundColor:"transparent"}});const selectWord=({state,dispatch})=>{let{selection}=state;let newSel=EditorSelection.create(selection.ranges.map(range=>state.wordAt(range.head)||EditorSelection.cursor(range.head)),selection.mainIndex);if(newSel.eq(selection))return false;dispatch(state.update({selection:newSel}));return true};function findNextOccurrence(state,query){let{main,ranges}=state.selection;let word=state.wordAt(main.head),fullWord=word&&word.from==main.from&&word.to==main.to;for(let cycled=false,cursor=new SearchCursor(state.doc,query,ranges[ranges.length-1].to);;){cursor.next();if(cursor.done){if(cycled)return null;cursor=new SearchCursor(state.doc,query,0,Math.max(0,ranges[ranges.length-1].from-1));cycled=true}else{if(cycled&&ranges.some(r=>r.from==cursor.value.from))continue;if(fullWord){let word=state.wordAt(cursor.value.from);if(!word||word.from!=cursor.value.from||word.to!=cursor.value.to)continue}return cursor.value}}}const selectNextOccurrence=({state,dispatch})=>{let{ranges}=state.selection;if(ranges.some(sel=>sel.from===sel.to))return selectWord({state:state,dispatch:dispatch});let searchedText=state.sliceDoc(ranges[0].from,ranges[0].to);if(state.selection.ranges.some(r=>state.sliceDoc(r.from,r.to)!=searchedText))return false;let range=findNextOccurrence(state,searchedText);if(!range)return false;dispatch(state.update({selection:state.selection.addRange(EditorSelection.range(range.from,range.to),false),effects:EditorView.scrollIntoView(range.to)}));return true};const searchConfigFacet=Facet.define({combine(configs){return combineConfig(configs,{top:false,caseSensitive:false,literal:false,wholeWord:false,createPanel:view=>new SearchPanel(view)})}});function search(config){return config?[searchConfigFacet.of(config),searchExtensions]:searchExtensions}class SearchQuery{constructor(config){this.search=config.search;this.caseSensitive=!!config.caseSensitive;this.literal=!!config.literal;this.regexp=!!config.regexp;this.replace=config.replace||"";this.valid=!!this.search&&(!this.regexp||validRegExp(this.search));this.unquoted=this.unquote(this.search);this.wholeWord=!!config.wholeWord}unquote(text){return this.literal?text:text.replace(/\\([nrt\\])/g,(_,ch)=>ch=="n"?"\n":ch=="r"?"\r":ch=="t"?"\t":"\\")}eq(other){return this.search==other.search&&this.replace==other.replace&&this.caseSensitive==other.caseSensitive&&this.regexp==other.regexp&&this.wholeWord==other.wholeWord}create(){return this.regexp?new RegExpQuery(this):new StringQuery(this)}getCursor(state,from=0,to){let st=state.doc?state:EditorState.create({doc:state});if(to==null)to=st.doc.length;return this.regexp?regexpCursor(this,st,from,to):stringCursor(this,st,from,to)}}class QueryType{constructor(spec){this.spec=spec}}function stringCursor(spec,state,from,to){return new SearchCursor(state.doc,spec.unquoted,from,to,spec.caseSensitive?undefined:x=>x.toLowerCase(),spec.wholeWord?stringWordTest(state.doc,state.charCategorizer(state.selection.main.head)):undefined)}function stringWordTest(doc,categorizer){return(from,to,buf,bufPos)=>{if(bufPos>from||bufPos+buf.length<to){bufPos=Math.max(0,from-2);buf=doc.sliceString(bufPos,Math.min(doc.length,to+2))}return(categorizer(charBefore(buf,from-bufPos))!=CharCategory.Word||categorizer(charAfter(buf,from-bufPos))!=CharCategory.Word)&&(categorizer(charAfter(buf,to-bufPos))!=CharCategory.Word||categorizer(charBefore(buf,to-bufPos))!=CharCategory.Word)}}class StringQuery extends QueryType{constructor(spec){super(spec)}nextMatch(state,curFrom,curTo){let cursor=stringCursor(this.spec,state,curTo,state.doc.length).nextOverlapping();if(cursor.done)cursor=stringCursor(this.spec,state,0,curFrom).nextOverlapping();return cursor.done?null:cursor.value}prevMatchInRange(state,from,to){for(let pos=to;;){let start=Math.max(from,pos-1e4-this.spec.unquoted.length);let cursor=stringCursor(this.spec,state,start,pos),range=null;while(!cursor.nextOverlapping().done)range=cursor.value;if(range)return range;if(start==from)return null;pos-=1e4}}prevMatch(state,curFrom,curTo){return this.prevMatchInRange(state,0,curFrom)||this.prevMatchInRange(state,curTo,state.doc.length)}getReplacement(_result){return this.spec.unquote(this.spec.replace)}matchAll(state,limit){let cursor=stringCursor(this.spec,state,0,state.doc.length),ranges=[];while(!cursor.next().done){if(ranges.length>=limit)return null;ranges.push(cursor.value)}return ranges}highlight(state,from,to,add){let cursor=stringCursor(this.spec,state,Math.max(0,from-this.spec.unquoted.length),Math.min(to+this.spec.unquoted.length,state.doc.length));while(!cursor.next().done)add(cursor.value.from,cursor.value.to)}}function regexpCursor(spec,state,from,to){return new RegExpCursor(state.doc,spec.search,{ignoreCase:!spec.caseSensitive,test:spec.wholeWord?regexpWordTest(state.charCategorizer(state.selection.main.head)):undefined},from,to)}function charBefore(str,index){return str.slice(findClusterBreak(str,index,false),index)}function charAfter(str,index){return str.slice(index,findClusterBreak(str,index))}function regexpWordTest(categorizer){return(_from,_to,match)=>!match[0].length||(categorizer(charBefore(match.input,match.index))!=CharCategory.Word||categorizer(charAfter(match.input,match.index))!=CharCategory.Word)&&(categorizer(charAfter(match.input,match.index+match[0].length))!=CharCategory.Word||categorizer(charBefore(match.input,match.index+match[0].length))!=CharCategory.Word)}class RegExpQuery extends QueryType{nextMatch(state,curFrom,curTo){let cursor=regexpCursor(this.spec,state,curTo,state.doc.length).next();if(cursor.done)cursor=regexpCursor(this.spec,state,0,curFrom).next();return cursor.done?null:cursor.value}prevMatchInRange(state,from,to){for(let size=1;;size++){let start=Math.max(from,to-size*1e4);let cursor=regexpCursor(this.spec,state,start,to),range=null;while(!cursor.next().done)range=cursor.value;if(range&&(start==from||range.from>start+10))return range;if(start==from)return null}}prevMatch(state,curFrom,curTo){return this.prevMatchInRange(state,0,curFrom)||this.prevMatchInRange(state,curTo,state.doc.length)}getReplacement(result){return this.spec.unquote(this.spec.replace.replace(/\$([$&\d+])/g,(m,i)=>i=="$"?"$":i=="&"?result.match[0]:i!="0"&&+i<result.match.length?result.match[i]:m))}matchAll(state,limit){let cursor=regexpCursor(this.spec,state,0,state.doc.length),ranges=[];while(!cursor.next().done){if(ranges.length>=limit)return null;ranges.push(cursor.value)}return ranges}highlight(state,from,to,add){let cursor=regexpCursor(this.spec,state,Math.max(0,from-250),Math.min(to+250,state.doc.length));while(!cursor.next().done)add(cursor.value.from,cursor.value.to)}}const setSearchQuery=StateEffect.define();const togglePanel=StateEffect.define();const searchState=StateField.define({create(state){return new SearchState(defaultQuery(state).create(),null)},update(value,tr){for(let effect of tr.effects){if(effect.is(setSearchQuery))value=new SearchState(effect.value.create(),value.panel);else if(effect.is(togglePanel))value=new SearchState(value.query,effect.value?createSearchPanel:null)}return value},provide:f=>showPanel.from(f,val=>val.panel)});function getSearchQuery(state){let curState=state.field(searchState,false);return curState?curState.query.spec:defaultQuery(state)}function searchPanelOpen(state){var _a;return((_a=state.field(searchState,false))===null||_a===void 0?void 0:_a.panel)!=null}class SearchState{constructor(query,panel){this.query=query;this.panel=panel}}const matchMark=Decoration.mark({class:"cm-searchMatch"}),selectedMatchMark=Decoration.mark({class:"cm-searchMatch cm-searchMatch-selected"});const searchHighlighter=ViewPlugin.fromClass(class{constructor(view){this.view=view;this.decorations=this.highlight(view.state.field(searchState))}update(update){let state=update.state.field(searchState);if(state!=update.startState.field(searchState)||update.docChanged||update.selectionSet||update.viewportChanged)this.decorations=this.highlight(state)}highlight({query,panel}){if(!panel||!query.spec.valid)return Decoration.none;let{view}=this;let builder=new RangeSetBuilder;for(let i=0,ranges=view.visibleRanges,l=ranges.length;i<l;i++){let{from,to}=ranges[i];while(i<l-1&&to>ranges[i+1].from-2*250)to=ranges[++i].to;query.highlight(view.state,from,to,(from,to)=>{let selected=view.state.selection.ranges.some(r=>r.from==from&&r.to==to);builder.add(from,to,selected?selectedMatchMark:matchMark)})}return builder.finish()}},{decorations:v=>v.decorations});function searchCommand(f){return view=>{let state=view.state.field(searchState,false);return state&&state.query.spec.valid?f(view,state):openSearchPanel(view)}}const findNext=searchCommand((view,{query})=>{let{to}=view.state.selection.main;let next=query.nextMatch(view.state,to,to);if(!next)return false;view.dispatch({selection:{anchor:next.from,head:next.to},scrollIntoView:true,effects:announceMatch(view,next),userEvent:"select.search"});return true});const findPrevious=searchCommand((view,{query})=>{let{state}=view,{from}=state.selection.main;let range=query.prevMatch(state,from,from);if(!range)return false;view.dispatch({selection:{anchor:range.from,head:range.to},scrollIntoView:true,effects:announceMatch(view,range),userEvent:"select.search"});return true});const selectMatches=searchCommand((view,{query})=>{let ranges=query.matchAll(view.state,1e3);if(!ranges||!ranges.length)return false;view.dispatch({selection:EditorSelection.create(ranges.map(r=>EditorSelection.range(r.from,r.to))),userEvent:"select.search.matches"});return true});const selectSelectionMatches=({state,dispatch})=>{let sel=state.selection;if(sel.ranges.length>1||sel.main.empty)return false;let{from,to}=sel.main;let ranges=[],main=0;for(let cur=new SearchCursor(state.doc,state.sliceDoc(from,to));!cur.next().done;){if(ranges.length>1e3)return false;if(cur.value.from==from)main=ranges.length;ranges.push(EditorSelection.range(cur.value.from,cur.value.to))}dispatch(state.update({selection:EditorSelection.create(ranges,main),userEvent:"select.search.matches"}));return true};const replaceNext=searchCommand((view,{query})=>{let{state}=view,{from,to}=state.selection.main;if(state.readOnly)return false;let next=query.nextMatch(state,from,from);if(!next)return false;let changes=[],selection,replacement;let announce=[];if(next.from==from&&next.to==to){replacement=state.toText(query.getReplacement(next));changes.push({from:next.from,to:next.to,insert:replacement});next=query.nextMatch(state,next.from,next.to);announce.push(EditorView.announce.of(state.phrase("replaced match on line $",state.doc.lineAt(from).number)+"."))}if(next){let off=changes.length==0||changes[0].from>=next.to?0:next.to-next.from-replacement.length;selection={anchor:next.from-off,head:next.to-off};announce.push(announceMatch(view,next))}view.dispatch({changes:changes,selection:selection,scrollIntoView:!!selection,effects:announce,userEvent:"input.replace"});return true});const replaceAll=searchCommand((view,{query})=>{if(view.state.readOnly)return false;let changes=query.matchAll(view.state,1e9).map(match=>{let{from,to}=match;return{from:from,to:to,insert:query.getReplacement(match)}});if(!changes.length)return false;let announceText=view.state.phrase("replaced $ matches",changes.length)+".";view.dispatch({changes:changes,effects:EditorView.announce.of(announceText),userEvent:"input.replace.all"});return true});function createSearchPanel(view){return view.state.facet(searchConfigFacet).createPanel(view)}function defaultQuery(state,fallback){var _a,_b,_c,_d;let sel=state.selection.main;let selText=sel.empty||sel.to>sel.from+100?"":state.sliceDoc(sel.from,sel.to);if(fallback&&!selText)return fallback;let config=state.facet(searchConfigFacet);return new SearchQuery({search:((_a=fallback===null||fallback===void 0?void 0:fallback.literal)!==null&&_a!==void 0?_a:config.literal)?selText:selText.replace(/\n/g,"\\n"),caseSensitive:(_b=fallback===null||fallback===void 0?void 0:fallback.caseSensitive)!==null&&_b!==void 0?_b:config.caseSensitive,literal:(_c=fallback===null||fallback===void 0?void 0:fallback.literal)!==null&&_c!==void 0?_c:config.literal,wholeWord:(_d=fallback===null||fallback===void 0?void 0:fallback.wholeWord)!==null&&_d!==void 0?_d:config.wholeWord})}const openSearchPanel=view=>{let state=view.state.field(searchState,false);if(state&&state.panel){let panel=getPanel(view,createSearchPanel);if(!panel)return false;let searchInput=panel.dom.querySelector("[main-field]");if(searchInput&&searchInput!=view.root.activeElement){let query=defaultQuery(view.state,state.query.spec);if(query.valid)view.dispatch({effects:setSearchQuery.of(query)});searchInput.focus();searchInput.select()}}else{view.dispatch({effects:[togglePanel.of(true),state?setSearchQuery.of(defaultQuery(view.state,state.query.spec)):StateEffect.appendConfig.of(searchExtensions)]})}return true};const closeSearchPanel=view=>{let state=view.state.field(searchState,false);if(!state||!state.panel)return false;let panel=getPanel(view,createSearchPanel);if(panel&&panel.dom.contains(view.root.activeElement))view.focus();view.dispatch({effects:togglePanel.of(false)});return true};const searchKeymap=[{key:"Mod-f",run:openSearchPanel,scope:"editor search-panel"},{key:"F3",run:findNext,shift:findPrevious,scope:"editor search-panel",preventDefault:true},{key:"Mod-g",run:findNext,shift:findPrevious,scope:"editor search-panel",preventDefault:true},{key:"Escape",run:closeSearchPanel,scope:"editor search-panel"},{key:"Mod-Shift-l",run:selectSelectionMatches},{key:"Alt-g",run:gotoLine},{key:"Mod-d",run:selectNextOccurrence,preventDefault:true}];class SearchPanel{constructor(view){this.view=view;let query=this.query=view.state.field(searchState).query.spec;this.commit=this.commit.bind(this);this.searchField=elt("input",{value:query.search,placeholder:phrase(view,"Find"),"aria-label":phrase(view,"Find"),class:"cm-textfield",name:"search",form:"","main-field":"true",onchange:this.commit,onkeyup:this.commit});this.replaceField=elt("input",{value:query.replace,placeholder:phrase(view,"Replace"),"aria-label":phrase(view,"Replace"),class:"cm-textfield",name:"replace",form:"",onchange:this.commit,onkeyup:this.commit});this.caseField=elt("input",{type:"checkbox",name:"case",form:"",checked:query.caseSensitive,onchange:this.commit});this.reField=elt("input",{type:"checkbox",name:"re",form:"",checked:query.regexp,onchange:this.commit});this.wordField=elt("input",{type:"checkbox",name:"word",form:"",checked:query.wholeWord,onchange:this.commit});function button(name,onclick,content){return elt("button",{class:"cm-button",name:name,onclick:onclick,type:"button"},content)}this.dom=elt("div",{onkeydown:e=>this.keydown(e),class:"cm-search"},[this.searchField,button("next",()=>findNext(view),[phrase(view,"next")]),button("prev",()=>findPrevious(view),[phrase(view,"previous")]),button("select",()=>selectMatches(view),[phrase(view,"all")]),elt("label",null,[this.caseField,phrase(view,"match case")]),elt("label",null,[this.reField,phrase(view,"regexp")]),elt("label",null,[this.wordField,phrase(view,"by word")]),...view.state.readOnly?[]:[elt("br"),this.replaceField,button("replace",()=>replaceNext(view),[phrase(view,"replace")]),button("replaceAll",()=>replaceAll(view),[phrase(view,"replace all")]),elt("button",{name:"close",onclick:()=>closeSearchPanel(view),"aria-label":phrase(view,"close"),type:"button"},["×"])]])}commit(){let query=new SearchQuery({search:this.searchField.value,caseSensitive:this.caseField.checked,regexp:this.reField.checked,wholeWord:this.wordField.checked,replace:this.replaceField.value});if(!query.eq(this.query)){this.query=query;this.view.dispatch({effects:setSearchQuery.of(query)})}}keydown(e){if(runScopeHandlers(this.view,e,"search-panel")){e.preventDefault()}else if(e.keyCode==13&&e.target==this.searchField){e.preventDefault();(e.shiftKey?findPrevious:findNext)(this.view)}else if(e.keyCode==13&&e.target==this.replaceField){e.preventDefault();replaceNext(this.view)}}update(update){for(let tr of update.transactions)for(let effect of tr.effects){if(effect.is(setSearchQuery)&&!effect.value.eq(this.query))this.setQuery(effect.value)}}setQuery(query){this.query=query;this.searchField.value=query.search;this.replaceField.value=query.replace;this.caseField.checked=query.caseSensitive;this.reField.checked=query.regexp;this.wordField.checked=query.wholeWord}mount(){this.searchField.select()}get pos(){return 80}get top(){return this.view.state.facet(searchConfigFacet).top}}function phrase(view,phrase){return view.state.phrase(phrase)}const AnnounceMargin=30;const Break=/[\s\.,:;?!]/;function announceMatch(view,{from,to}){let line=view.state.doc.lineAt(from),lineEnd=view.state.doc.lineAt(to).to;let start=Math.max(line.from,from-AnnounceMargin),end=Math.min(lineEnd,to+AnnounceMargin);let text=view.state.sliceDoc(start,end);if(start!=line.from){for(let i=0;i<AnnounceMargin;i++)if(!Break.test(text[i+1])&&Break.test(text[i])){text=text.slice(i);break}}if(end!=lineEnd){for(let i=text.length-1;i>text.length-AnnounceMargin;i--)if(!Break.test(text[i-1])&&Break.test(text[i])){text=text.slice(0,i);break}}return EditorView.announce.of(`${view.state.phrase("current match")}. ${text} ${view.state.phrase("on line")} ${line.number}.`)}const baseTheme=EditorView.baseTheme({".cm-panel.cm-search":{padding:"2px 6px 4px",position:"relative","& [name=close]":{position:"absolute",top:"0",right:"4px",backgroundColor:"inherit",border:"none",font:"inherit",padding:0,margin:0},"& input, & button, & label":{margin:".2em .6em .2em 0"},"& input[type=checkbox]":{marginRight:".2em"},"& label":{fontSize:"80%",whiteSpace:"pre"}},"&light .cm-searchMatch":{backgroundColor:"#ffff0054"},"&dark .cm-searchMatch":{backgroundColor:"#00ffff8a"},"&light .cm-searchMatch-selected":{backgroundColor:"#ff6a0054"},"&dark .cm-searchMatch-selected":{backgroundColor:"#ff00ff8a"}});const searchExtensions=[searchState,Prec.lowest(searchHighlighter),baseTheme];export{RegExpCursor,SearchCursor,SearchQuery,closeSearchPanel,findNext,findPrevious,getSearchQuery,gotoLine,highlightSelectionMatches,openSearchPanel,replaceAll,replaceNext,search,searchKeymap,searchPanelOpen,selectMatches,selectNextOccurrence,selectSelectionMatches,setSearchQuery};