forked from phcode-dev/staging.phcode.dev
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathIndentHelper.js
More file actions
1 lines (1 loc) · 5.38 KB
/
IndentHelper.js
File metadata and controls
1 lines (1 loc) · 5.38 KB
1
define(function(require,exports,module){const _=require("thirdparty/lodash"),CodeMirror=require("thirdparty/CodeMirror/lib/codemirror"),PreferencesManager=require("preferences/PreferencesManager"),EditorPreferences=require("./EditorPreferences"),SOFT_TABS=EditorPreferences.SOFT_TABS,INDENT_REGEX=/^(?:( )+|\t+)/,INDENT_TYPE_SPACE="space",INDENT_TYPE_TAB="tab";function makeIndentsMap(editor,ignoreSingleSpaces,scanLineLimit){const indents=new Map;let previousSize=0,previousIndentType;const totalLines=editor.lineCount();let key,scanLimit=scanLineLimit?Math.min(scanLineLimit,totalLines):totalLines;for(let i=0;i<scanLimit;i++){const line=editor.document.getLine(i);if(!line)continue;let indent,indentType,use,weight,entry;const matches=line.match(INDENT_REGEX);if(null===matches)previousSize=0,previousIndentType="";else{if(indent=matches[0].length,indentType=matches[1]?INDENT_TYPE_SPACE:INDENT_TYPE_TAB,ignoreSingleSpaces&&indentType===INDENT_TYPE_SPACE&&1===indent)continue;indentType!==previousIndentType&&(previousSize=0),previousIndentType=indentType,use=1,weight=0;const indentDifference=indent-previousSize;if(previousSize=indent,0===indentDifference)use=0,weight=1;else{const absoluteIndentDifference=indentDifference>0?indentDifference:-indentDifference;key=encodeIndentsKey(indentType,absoluteIndentDifference)}entry=void 0===(entry=indents.get(key))?[1,0]:[entry[0]+use,entry[1]+weight],indents.set(key,entry)}}return indents}function encodeIndentsKey(indentType,indentAmount){const typeCharacter=indentType===INDENT_TYPE_SPACE?"s":"t";return typeCharacter+String(indentAmount)}function decodeIndentsKey(indentsKey){const keyHasTypeSpace="s"===indentsKey[0],type=keyHasTypeSpace?INDENT_TYPE_SPACE:INDENT_TYPE_TAB,amount=Number(indentsKey.slice(1));return{type:type,amount:amount}}function getMostUsedKey(indents){let result,maxUsed=0,maxWeight=0;for(const[key,[usedCount,weight]]of indents)(usedCount>maxUsed||usedCount===maxUsed&&weight>maxWeight)&&(maxUsed=usedCount,maxWeight=weight,result=key);return result}function makeIndentString(type,amount){const indentCharacter=type===INDENT_TYPE_SPACE?" ":"\t";return indentCharacter.repeat(amount)}function _detectIndent(scanLineLimit){const editor=this;let indents=makeIndentsMap(editor,!0,scanLineLimit);0===indents.size&&(indents=makeIndentsMap(editor,!1,scanLineLimit));const keyOfMostUsedIndent=getMostUsedKey(indents);let type,amount=0,indent="";return void 0!==keyOfMostUsedIndent&&(({type:type,amount:amount}=decodeIndentsKey(keyOfMostUsedIndent)),indent=makeIndentString(type,amount)),{amount:amount,type:type,indent:indent}}function _addIndentAtEachSelection(selections){let self=this;var instance=this._codeMirror,usingTabs=instance.getOption("indentWithTabs"),indentUnit=instance.getOption("indentUnit"),edits=[];_.each(selections,function(sel){var indentStr="",i,numSpaces;if(usingTabs)indentStr="\t";else for(numSpaces=indentUnit-sel.start.ch%indentUnit,i=0;i<numSpaces;i++)indentStr+=" ";edits.push({edit:{text:indentStr,start:sel.start}})}),this.document.doMultipleEdits(edits)}function _autoIndentEachSelection(selections){let self=this;var instance=this._codeMirror,lineLengths={};_.each(selections,function(sel){lineLengths[sel.start.line]=instance.getLine(sel.start.line).length}),CodeMirror.commands.indentAuto(instance);var changed=!1,newSelections=this.getSelections();newSelections.length===selections.length?_.each(selections,function(sel,index){var newSel=newSelections[index];if(0!==CodeMirror.cmpPos(sel.start,newSel.start)||0!==CodeMirror.cmpPos(sel.end,newSel.end)||instance.getLine(sel.start.line).length!==lineLengths[sel.start.line])return changed=!0,!1}):changed=!0,changed||CodeMirror.commands.indentMore(instance)}function _handleTabKey(){let self=this;var instance=self._codeMirror,selectionType="indentAuto",selections=self.getSelections();switch(_.each(selections,function(sel){if(sel.start.line!==sel.end.line)return selectionType="indentAtBeginning",!1;sel.end.ch>0&&sel.end.ch>=instance.getLine(sel.end.line).search(/\S/)&&(selectionType="indentAtSelection")}),selectionType){case"indentAtBeginning":CodeMirror.commands.indentMore(instance);break;case"indentAtSelection":self._addIndentAtEachSelection(selections);break;case"indentAuto":self._autoIndentEachSelection(selections)}}function _handleSoftTabNavigation(direction,functionName){let self=this;var instance=self._codeMirror,overallJump=null;if(!instance.getOption("indentWithTabs")&&PreferencesManager.get(SOFT_TABS)){var indentUnit=instance.getOption("indentUnit");_.each(self.getSelections(),function(sel){if(0===CodeMirror.cmpPos(sel.start,sel.end)){var cursor=sel.start,jump=0===indentUnit?1:cursor.ch%indentUnit,line=instance.getLine(cursor.line);if(-1!==line.substr(0,cursor.ch).search(/\S/)?jump=null:1===direction?(indentUnit&&(jump=indentUnit-jump),(cursor.ch+jump>line.length||-1!==line.substr(cursor.ch,jump).search(/\S/))&&(jump=null)):(0===jump&&(jump=indentUnit),jump=cursor.ch-jump<0?null:-jump),null===jump||null!==overallJump&&overallJump!==jump)return overallJump=null,!1;overallJump=jump}})}null===overallJump&&(overallJump=direction),instance[functionName](overallJump,"char")}function addHelpers(Editor){Editor.prototype._addIndentAtEachSelection=_addIndentAtEachSelection,Editor.prototype._autoIndentEachSelection=_autoIndentEachSelection,Editor.prototype._handleTabKey=_handleTabKey,Editor.prototype._handleSoftTabNavigation=_handleSoftTabNavigation,Editor.prototype._detectIndent=_detectIndent}exports.addHelpers=addHelpers});