Artifact [3521a70fa7] Вы: nobody
Вход

Artifact 3521a70fa7013adef649ab9193d294f4b9ed02a2:


$engine JScript
$uname textEditorExt
$dname Расширение редактора текстов
$addin global
$addin stdlib

/* ======================================================================

AUTHOR: Василий Фролов aka Палыч, palytsh@mail.ru

DATE: 02.09.2011

COMMENT: 

   1. Макросы НайтиВыделенныйТекстВниз и НайтиВыделенныйТекстВверх. 
Горячие клавиши Ctrl + Down и Ctrl + Up.

   2. Макрос КлонироватьТекст. Позволяет скопировать выделенный фрагмент 
текста без использования буфера обмена. Горячие клавиши Ctrl + D.

   3. Макросы OnPressEnterInComment, OnPressBackspaceInComment, 
OnPressDeleteInComment предназначены для более удобного редактирования 
многострочных комментариев. Вызываются неявно при нажатии соответствующих 
клавиш.

========================================================================= */

stdlib.require('TextWindow.js', SelfScript);

function getPredefinedHotkeys(predef){
    predef.setVersion(5);
    predef.add("НайтиВыделенныйТекстВниз", "Ctrl + Down");
    predef.add("НайтиВыделенныйТекстВверх", "Ctrl + Up");
    predef.add("КлонироватьТекст", "Ctrl + D");
    predef.add("OnPressEnterInComment", "Enter");
    predef.add("OnPressDeleteInComment", "Del");
    predef.add("OnPressBackspaceInComment", "BkSpace");
    predef.add("Преобразовать регистр: ПРОПИСНЫЕ", "Ctrl + Shift + U");
    predef.add("Преобразовать регистр: строчные", "Ctrl + U");
}

function macrosНайтиВыделенныйТекстВниз(){
    selectNextPattern(1);
}

function macrosНайтиВыделенныйТекстВверх(){
    selectNextPattern(-1);
}

function macrosПоменятьОперандыПрисваиванияМестами() {
    
    var w = GetTextWindow(); 
    if (!w) return false;
    
    var selText = w.GetSelectedText();
    if (selText == '') return;
    
    var sel = w.GetSelection();
    
    var lines = StringUtils.toLines(selText);
    for(var lineNo = 0; lineNo < lines.length; lineNo++)
        lines[lineNo] = lines[lineNo].replace(/(\s*)(\S*.+?)\s*=\s*(\S*.+)\s*;/, "$1$3=$2;");
    
    w.SetSelectedText(StringUtils.fromLines(lines));
    // Восстановим исходное выделение.
    w.SetSelection(sel.beginRow, sel.beginCol, sel.endRow, sel.endCol);
    
    if (lines.length > 1)
    {
        // Если было выделено несколько строк, выровняем в них по знакам '='.
        var formatScript = addins.byUniqueName('format_script');
        if (formatScript)
        {
            formatScript.invokeMacros('ВыровнятьЗнакиРавно');
            // И снова восстановим исходное выделение.
            w.SetSelection(sel.beginRow, sel.beginCol, sel.endRow, sel.endCol);            
        }
    }
}

SelfScript.Self['macrosПреобразовать регистр: ПРОПИСНЫЕ'] = function() {
    processSelectedText(function(selText){ return selText.toUpperCase(); });
}

SelfScript.Self['macrosПреобразовать регистр: строчные'] = function() {
    processSelectedText(function(selText){ return selText.toLowerCase(); });
}

function selectNextPattern(dir){
    //debugger;
    var w = GetTextWindow(); //snegopat.activeTextWindow();
    if (!w) return false;
    
//debugger;    
    
    var sel = w.getSelection();
    var selText = w.selectedText();
    if (selText == '') return false;

    var row = dir < 0 ? 
        searchPatternUp(w, selText, sel.beginRow) :
        searchPatternDown(w, selText, sel.beginRow);
    
    if (!row) return false;
    var str = w.line(row);
    var col = 1 + str.indexOf(selText);
    
    w.setCaretPos(1, 1);
    w.setSelection(row, col, row, col + selText.length);
    w.setCaretPos(row, col);
    w.setSelection(row, col, row, col + selText.length);
    
    return true;
}

function searchPatternDown(doc, pattern, startRow){
    var q = 0;
    for (var i = startRow + 1; i <= doc.linesCount(); i++){
        
        if (++q > 10000) return null;
        
        var str = doc.line(i);
        var j = str.indexOf(pattern);
        if (j > -1) return i;
    }
    return null;
}

function searchPatternUp(doc, pattern, startRow){
//debugger;    
    var q = 0;
    for (var i = startRow - 1; i >= 1; i--){
        
        if (++q > 10000) return null;
        
        var str = doc.line(i);
        var j = str.indexOf(pattern);
        if (j > -1) return i;
    }
    return null;
}

function macrosКлонироватьТекст(){
    var w = GetTextWindow();//snegopat.activeTextWindow();
    if (!w) return false;
    
    var sel = w.getSelection();
    var selText = w.selectedText();
    if (selText != ''){            
        w.SetSelectedText(selText + "\n" + selText);
    }
    else{
        // Если ничего не выделено, склонируем текущую строку
        var pos = w.getCaretPos();
        w.setSelection(pos.beginRow, 1, pos.beginRow, 1 + w.line(pos.beginRow).length);
        w.SetSelectedText(w.selectedText() + "\n" + w.selectedText());
    }
}

function macrosOnPressEnterInComment(){
    var w = GetTextWindow();//snegopat.activeTextWindow();
    if (!w) return false;
    
    var pos = w.getCaretPos();
    var str = w.line(pos.beginRow);
    if (str.match(/^\s*\/\/\s*[^\s]+/ig)) {     

        // Если курсор установлен левее символов комментария, то не обрабатываем нажатие,
        // чтобы добавлялась пустая строка, как и ожидается.
        if (pos.beginCol <= str.search('//') + 1)
            return false;

        // Это непустой комментарий - добавляем комментарий ниже 
        // с отступом как в предыдущей строке.
        var newStr = getCommentStringHeader(str);

        // Если справа от курсора есть текст, перенесем его 
        // на новую строку комментария.
        if (str.length >= pos.endCol) {
            var tail = str.substr(pos.beginCol - 1, str.length - pos.beginCol + 1);
            w.ReplaceLine(pos.beginRow, str.substr(0, pos.beginCol - 1));    // отрезаем хвост от текущей строки
            newStr = newStr + tail.replace(/^\s*/ig, "");
        }
        var newCaretRow = 1 + pos.beginRow;
        w.InsertLine(newCaretRow, newStr);
        w.setCaretPos(newCaretRow, 1 + newStr.length);
        return true;
    }
    return false;
}

function macrosOnPressDeleteInComment(){
    var w = GetTextWindow();//snegopat.activeTextWindow();
    if (!w) return false;

    if (w.selectedText() != ""){
        return false;    /// TODO: обработать этот вариант.
    }
    
    var pos = w.getCaretPos();
    
    if (pos.beginRow == w.linesCount) return false;
    
    var str = w.line(pos.beginRow);
    
    if (!isCommentString(str)) return false;
    
    if (pos.endCol > str.length){
        // Курсор стоит в самом конце строки и при нажатии 
        // Delete следующая строка должна приклеиться в конец текущей.
        var newTail = w.line(1 + pos.beginRow);
        
        if (!isCommentString(newTail)) return false;
        
        newTail = newTail.replace(/^\s*\/\/*\/\s*/ig, ""); 
        if (str.match(/[^\s]$/ig)) newTail = " " + newTail;
        
        w.ReplaceLine(pos.beginRow, str + newTail);
        w.DeleteLine(1 + pos.beginRow);
        w.setCaretPos(pos.beginRow, pos.beginCol);
        return true;
    }
    return false;
}

function macrosOnPressBackspaceInComment(){
    var w = GetTextWindow();//snegopat.activeTextWindow();
    if (!w) return false;

    if (w.selectedText() != ""){
        return false;    /// TODO: обработать этот вариант.
    }
    
    var pos = w.getCaretPos();
    if (pos.beginRow == 1) return false;    // И так уже стоим в первой строке.
    
    // Обрабатываем только если стоим  в самом начале строки и 
    // если эта и предыдущая строки являются комментариями.
    if (pos.beginCol > 1) return false;
    
    var str = w.line(pos.beginRow);
    if (!isCommentString(str)) return false;
    
    var prevStr = w.line(pos.beginRow - 1);
    if (!isCommentString(prevStr)) return false;
    
    // Курсор стоит в самом начале строки и при нажатии 
    // Backspace текущая строка должна приклеиться в конец предыдущей.
    var newTail = str.replace(/^\s*\/\/*\/\s*/ig, ""); 
    if (prevStr.match(/[^\s]$/ig)) newTail = " " + newTail;
    
    w.setSelection(pos.beginRow - 1, 1, pos.beginRow, 
        w.line(pos.beginRow).length + 1);
    w.SetSelectedText(prevStr + newTail);
    
    w.setCaretPos(pos.beginRow - 1, 1 + prevStr.length);
    
    return true;
}

function isCommentString(str){
    return null != str.match(/^\s*\/\//ig);
}

function getTextBlockOffset(str){
    var match = str.match(/^([\s]+)/ig);
    var res = !match ? "" : match[0];
    return res;
}

function getCommentStringHeader(str){
    var match = str.match(/^([\s]*\/\/*\/[\s]?)*/ig);
    var res = !match ? "" : match[0];
    return res;
}

function processSelectedText(selTextHandler, doNotRestoreSelection) {
    
    var w = GetTextWindow(); 
    if (!w) return false;    
    
    var sel = w.GetSelection();            
    var selText = w.GetSelectedText();
    
    try 
    {
        selText = selTextHandler.call(null, selText);
    }
    catch (e)
    {
       Message(e.description);
       return;
    }        
    
    w.SetSelectedText(selText);
    
    // Восстановим исходное выделение.
    if (!doNotRestoreSelection)
        w.SetSelection(sel.beginRow, sel.beginCol, sel.endRow, sel.endCol);
}