watch_ext.js at tip Вы: nobody
Вход

File watch_ext.js from the latest check-in


$engine JScript
$uname watch_ext
$dname Расширенное табло
$addin stdcommands
$addin stdlib
$addin global

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

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

global.connectGlobals(SelfScript);


var logger = Log4js.getLogger(SelfScript.uniqueName);
var appender = new Log4js.BrowserConsoleAppender();
appender.setLayout(new Log4js.PatternLayout(Log4js.PatternLayout.TTCC_CONVERSION_PATTERN));
logger.addAppender(appender);
logger.setLevel(Log4js.Level.ERROR);
var loggerInfo = Log4js.getLogger(SelfScript.uniqueName+"info");
loggerInfo.addAppender(appender);
loggerInfo.setLevel(Log4js.Level.INFO);



events.connect(v8debug, "onDebugEvent", SelfScript.Self)
stdcommands.CDebug.Break.addHandler(SelfScript.self, "onStopDebug")

var form = loadScriptForm(SelfScript.fullPath.replace(/js$/i, "ssf"), SelfScript.self)
form.КлючСохраненияПоложенияОкна = "watch_ext"
form.ПеременныеОтладки.Колонки.Добавить("Modified")
var rModule = form.ПеременныеОтладки.Строки.Добавить();
rModule.Название = "Переменные модуля";
var rParams = form.ПеременныеОтладки.Строки.Добавить();
rParams.Название = "Параметры метода";
var rLocal = form.ПеременныеОтладки.Строки.Добавить();
rLocal.Название = "Локальные переменные";
var rHands = form.ПеременныеОтладки.Строки.Добавить();
rHands.Название = "Табло";
getRow(rHands, '');
var colorRed = v8new("Цвет", 255, 0, 0), colorGray = v8new("Цвет", 200, 200, 200)
var curViewHwnd = "";
var curSyntaxAnalysis = null;
var needTestModified = false;
var timerExpressionUpdater = null;
var valueBrkptCond = "";

SelfScript.self['macrosОткрыть окно отладки'] = function()
{
	
    form.Open() // Покажем окно
}

SelfScript.self['macrosПереключитьавтообновление'] = function()
{
    logger.debug(this.name);
    if (!timerExpressionUpdater){
        logger.debug("timerExpressionUpdater: "+timerExpressionUpdater);
    }
    else {

        timerExpressionUpdater.stop = !timerExpressionUpdater.stop;
        //Message("Теперь автообновление "+timerExpressionUpdater.stop?"остановленно" : "включено");
        loggerInfo.info("timerExpressionUpdater.stop is "+timerExpressionUpdater.stop);
    }
}

/* Возвращает название макроса по умолчанию - вызывается, когда пользователь 
дважды щелкает мышью по названию скрипта в окне Снегопата. */
function getDefaultMacros() {
    return 'Переключитьавтообновление';
}

function setTimeForUpdateExpression(timeout) {

    logger.debug(this.name);
    if (!timerExpressionUpdater){
    } else {
        if ((timerExpressionUpdater.timeout + timeout) < 0 ) {
            Message("Время ниже нуля нельзя. "+(timerExpressionUpdater.timeout + timeout));
            return;
        }
        timerExpressionUpdater.timeout = timerExpressionUpdater.timeout + timeout;
    }

    logger.debug(timerExpressionUpdater.timeout);

}

function hookBrkptCond(dlgInfo)
{
    if(dlgInfo.stage == openModalWnd)
    {
        dlgInfo.form.getControl("Condition").value = valueBrkptCond;

        dlgInfo.cancel = false;
        dlgInfo.result = mbaOk;
    }
}

function hookBrkptCondAuto(dlgInfo)
{
    if(dlgInfo.stage == openModalWnd)
    {
        dlgInfo.form.getControl("Condition").value = valueBrkptCond;

        dlgInfo.cancel = true   // Отменяем показ диалога
        dlgInfo.result = 1      // как будто в нем нажали Ок
    }
}



SelfScript.self['macrosУстановить точку останова по условию'] = function(){
    if (!form.ЭлементыФормы.ПеременныеОтладки.ТекущаяСтрока) {
        logger.error("Не определенна текущая строка для выражения");
        return;
    }
    
    events.connect(windows, "onDoModal", SelfScript.self, "hookBrkptCond");
    var state = stdcommands.CDebug.BrkptCond.getState();
    var curRow = form.ЭлементыФормы.ПеременныеОтладки.ТекущаяСтрока;
    var curValue = ''+curRow.Значение;
    var name = fullName(curRow);
    valueBrkptCond = ""+ name + " = "+curValue;
    stdcommands.CDebug.BrkptCond.send();
    events.disconnect(windows, "onDoModal", SelfScript.self, "hookBrkptCond");
    
}

SelfScript.self['macrosУстановить точку останова по условию для выделенных строк'] = function(){
    if (!form.ЭлементыФормы.ПеременныеОтладки.ТекущаяСтрока) {
        logger.error("Не определенна текущая строка для выражения");
        return;
    }

    var wnd = GetTextWindow();
    if(!wnd)
        return;
    view = wnd.GetView();

    var curRow = form.ЭлементыФормы.ПеременныеОтладки.ТекущаяСтрока;
    var curValue = ''+curRow.Значение;
    var name = fullName(curRow);
    valueBrkptCond = ""+ name + " = "+curValue;

    var vbs = addins.byUniqueName("vbs").object
    vbs.var0 = valueBrkptCond; vbs.var1 = "Введите выражение"; vbs.var2 = 0, vbs.var3 = false;
    if (vbs.DoEval("InputString(var0, var1, var2, var3)")) {
            valueBrkptCond  = vbs.var0;
    }
    if (valueBrkptCond.length = 0)
        return;

    events.connect(windows, "onDoModal", SelfScript.self, "hookBrkptCondAuto");
    var state = stdcommands.CDebug.BrkptCond.getState();

    sel = wnd.GetSelection();
    for (var i = sel.beginRow; i<sel.endRow; i++){
        stdcommands.CDebug.BrkptCond.send();
        wnd.SetCaretPos(i, sel.beginCol);
    }
    
    events.disconnect(windows, "onDoModal", SelfScript.self, "hookBrkptCondAuto");
    valueBrkptCond = "";
    loggerInfo.info("Точки останова установленны!");
    
}


SelfScript.self['macrosУвеличить период обновления на 1 сек. '] = function() {
    setTimeForUpdateExpression(1000);
}

SelfScript.self['macrosУменьшить период обновления на 1 сек. '] = function() {
    setTimeForUpdateExpression(-1000);
}

//TODO: Добавить вычисление выражения. 
function onDebugEvent(eventID, eventParam)
{
    logger.debug(this.name);
    logger.debug(eventID);
    if (!timerExpressionUpdater){
        logger.debug("timerExpressionUpdater не определен "+timerExpressionUpdater)
        timerExpressionUpdater = GetTimerExpressionUpdater();
    }
    //Message("SCRIPT " + eventID + ", " + eventParam);
    if(eventID == "{FE7C6DDD-7C99-42F8-BA14-CDD30EDF2EF1}")
    {
        var view = windows.getActiveView()
        form.Open() // Покажем окно
        if(view)
            view.activate()
    }
    else if(eventID == "{71501A9D-CD34-427D-81B6-562491BEF945}")
    {
        clearExpressions();
        timerExpressionUpdater.stopWatch();
    }
    if(eventID == "{5B5F928D-DF2D-4804-B2D0-B453163A2C4C}")
    {
        //Message("eventParam " + eventParam);
        if(eventParam == 37 || eventParam == 24 || eventParam == 30 )    // Остановились в точке останова
        {
            //Message("SCRIPT Остановились в точке останова")
            needTestModified = true
            fillLocalVariables()    // Заполним локальные переменные
            //events.connect(Designer, "onIdle", SelfScript.self) // Будем их обновлять
            timerExpressionUpdater.updateTimer();
        }
    }
}


function isDebugEvalEnabled()
{
    // Команда "Шагнуть в" неактивна - значит, мы не в останове. Считать переменные нельзя, возможен вылет
    var state = stdcommands.CDebug.StepIn.getState()
    return state && state.enabled
}

function onStopDebug()
{
    clearExpressions()
}

function onIdle()
{
    if(!isDebugEvalEnabled())
    {
        events.disconnect(Designer, "onIdle", SelfScript.self)
        return
    }
    try{
        updateDebugExpressions()
    }catch(e)
    {
        // Все ошибки будем гасить
    }
    events.disconnect(Designer, "onIdle", SelfScript.self)
}

function clearExpressions()
{
    rModule.Строки.Очистить()
    rParams.Строки.Очистить()
    rLocal.Строки.Очистить()
    if(form.Открыта())
        form.Закрыть()
}

function getRow(parent, name)
{
    var r = parent.Строки.Найти(name, "Название")
    if(!r)
    {
        r = parent.Строки.Добавить()
        r.Название = name
        r.Modified = 0
    }
    return r
}

function removeRows(parent, all)
{
    var del = []
    for(var k = new Enumerator(parent.Строки); !k.atEnd(); k.moveNext())
    {
        var r = k.item()
        if(!all[r.Название])
            del.push(r)
    }
    for(var k in del)
        parent.Строки.Удалить(del[k])
}

function fillLocalVariables()
{
    var wnd = GetTextWindow();
    if(!wnd)
        return
    view = wnd.GetView();
    title = "";
    if (!view){
    } else {
        if (view.mdObj && view.mdProp) {
            
            function getMdName(mdObj) {                             
                if (mdObj.parent && mdObj.parent.mdClass.name(1) != 'Конфигурация')
                    return getMdName(mdObj.parent) + '.' + mdObj.mdClass.name(1) + ' ' + mdObj.name;
                var cname = mdObj.mdClass.name(1);
                return  (cname ? cname + ' ' : '') + mdObj.name;
            }
            title = getMdName(view.mdObj) + ': ' + view.mdProp.name(1);
            
            if (wnd.GetHwnd() != curViewHwnd)
                curSyntaxAnalysis = null;
                curMdObject = wnd.GetHwnd();
        }
    }
    
    if (!curSyntaxAnalysis || !view){
        var mod = SyntaxAnalysis.AnalyseTextDocument(wnd);
        curSyntaxAnalysis = mod;
    } else {
        var mod = curSyntaxAnalysis;
    }
    
    var meth = mod.getActiveLineMethod()
    rModule.Значение = title;
    //debugger
    // Заполним переменные модуля
    var all = {}
    for(var k in mod.context.ModuleVars)
    {
        getRow(rModule, mod.context.ModuleVars[k])
        all[mod.context.ModuleVars[k]] = true
    }
    removeRows(rModule, all)
    if (!meth){
        rParams.Значение = "<Вне процедуры/функции>"
    } else {
        // Заполним параметры
        rParams.Значение = meth.Name;
        if(!meth.Params){

        }else{
            var all = {}
            for(var k in meth.Params)
            {
                getRow(rParams, meth.Params[k])
                all[meth.Params[k]] = true
            }
            removeRows(rParams, all)
        }
        // Заполним локальные переменные
        var all = {}
        for(var k in meth.DeclaredVars)
        {
            getRow(rLocal, meth.DeclaredVars[k])
            all[meth.DeclaredVars[k]] = true
        }
        for(var k in meth.AutomaticVars)
        {
            getRow(rLocal, meth.AutomaticVars[k])
            all[meth.AutomaticVars[k]] = true
        }
    }
    
    removeRows(rLocal, all)
    form.ЭлементыФормы.ПеременныеОтладки.Развернуть(rModule, false)
    form.ЭлементыФормы.ПеременныеОтладки.Развернуть(rParams, false)
    form.ЭлементыФормы.ПеременныеОтладки.Развернуть(rLocal, false)
    form.ЭлементыФормы.ПеременныеОтладки.Развернуть(rHands, false);
}

function setRowValue(row, value, type)
{
    if(needTestModified)
    {
        if(row.Modified == 0)   // Строка только что добавилась
            row.Modified = 1    // В следующий раз проверять строку на изменение
        else
            row.Modified = row.Значение !== value ? 2 : 1
    }
    row.Значение = value
    row.Тип = type
}

function updateOneExpression(row, parentName)
{
    // Рассчитаем отладочное значение в строке
    if (row.Название.length<1){
        setRowValue(row, '', '');
        return;
    }
    var expr = v8debug.eval(parentName + row.Название)
    // Установим значение и модифицированность
    setRowValue(row, expr.value, expr.type)
    // Переберем свойства вычисленного выражения
    var all = {}
    for(var k = 0; k < expr.propCount; k++)
    {
        var prop = expr.prop(k)
        var r = getRow(row, prop.name)
        all[prop.name] = true
        setRowValue(r, prop.value, prop.type)
        
        if(prop.expandable)
        {
            // Свойство имеет подсвойства, надо показывать плюсик
            if(!r.Строки.Количество()) // Для этого при необходимости добавим пустую строку
                r.Строки.Добавить().Название = "-"
                
            // Если свойство само развернуто, его надо тоже обновить
            if(form.ЭлементыФормы.ПеременныеОтладки.Развернут(r))
                updateOneExpression(r, parentName + row.Название + ".")
        }
        else
        {
            // Не разворачиваемое свойство, на всякий случай удалим подчиненные строки
            r.Строки.Очистить()
        }
    }
    removeRows(row, all)
}

function updateRows(parent)
{
    for(var rows = new Enumerator(parent.Строки); !rows.atEnd(); rows.moveNext())
        updateOneExpression(rows.item(), "")
}

function updateDebugExpressions()
{
    if(!form.Открыта())
        return
    //debugger
    updateRows(rModule)
    updateRows(rParams)
    updateRows(rLocal)
    updateRows(rHands);
    needTestModified = false
}

function fullName(row)
{
    logger.debug(this.name + " уровень "+row.Уровень());
    var t = row.Название
    if (row.Уровень() > 1){
        t = fullName(row.Родитель) +"."+t;
    }
    logger.debug(""+t);
    return t
}

function ПеременныеОтладкиВыбор(Элемент, ВыбраннаяСтрока, Колонка, СтандартнаяОбработка)
{
    //Message('ПеременныеОтладкиВыбор');
    var value = ВыбраннаяСтрока.val.Значение
    if(value.indexOf('\n') >= 0)
    {
        Message("Значение '" + fullName(ВыбраннаяСтрока.val) + "':", mInfo)
        Message(value)
    }
}

function ПеременныеОтладкиПриВыводеСтроки(Элемент, ОформлениеСтроки, ДанныеСтроки)
{
    if(ДанныеСтроки.val.Уровень() == 0)
        ОформлениеСтроки.val.ЦветФона = colorGray
    else
    {
        if(ДанныеСтроки.val.Modified == 2)
            ОформлениеСтроки.val.ЦветТекста = colorRed
        // Для строк с переносом строки покажем картинку, что на нее можно щелкнуть
        if(ДанныеСтроки.val.Значение.indexOf('\n') >= 0)
        {
            var cell = ОформлениеСтроки.val.Ячейки.Значение
            cell.ОтображатьКартинку = true
            cell.ИндексКартинки = 0
        }
    }
}

function ПеременныеОтладкиПередРазворачиванием(Элемент, Строка, Отказ)
{
    if(isDebugEvalEnabled())    // Если возможно вычисление отладочных выражений
    {
        var row = Строка.val
        if(row.Уровень() > 0)   // Это не строка с именем раздела
        {
            if(row.Строки.Количество() == 1 && row.Строки.Получить(0).Название == "-")
            {
                // Разворачиваем первый раз
                updateOneExpression(row, fullName(row.Родитель) + ".")
            }
        }
    }
}

function ПеременныеОтладкиПередНачаломДобавления(Элемент, Отказ, Копирование, Родитель){

    Message(Родитель.Наименование);
    if (!Родитель){
        Отказ = true;
        return;
    }
    
    //if (Родитель.Уровень() > 0){
    //    Отказ = true;
    //    return;
    //}
    
    if (Родитель.Наименование != rHands.Наименование){
        Отказ = true;
        return;
    }
    
}

function ПеременныеОтладкиНазваниеПриИзменении(Элемент) {

    updateOneExpression(form.ЭлементыФормы.ПеременныеОтладки.ТекущаяСтрока, "");
    
}


function GetTimerExpressionUpdater(){
    ////////////////////////////////////////////////////////////////////////////////////////
////{ TimerExpressionUpdater - переодически обновляем значения переменных
////

TimerExpressionUpdater = stdlib.Class.extend({

    construct : function() {
        this.timerId = 0;
        this.stop = false;
        this.timeout = 100;
        //this.startWatch();
    },

    updateTimer: function(){
        logger.debug(this.name);
        this.stopWatch();
        this.startWatch()
    },

    startWatch : function () {
        logger.debug(this.name + " "+ this.constructor.name);

        if (this.timerId)
            this.stopWatch();
        
        if (this.stop){
            logger.debug("Таймер отключен "+this.stop);
            return;
        }

        this.timerId = createTimer(this.timeout, this, 'onTimer');
    },

    stopWatch : function () {
        if (!this.timerId)
            return;
        killTimer(this.timerId);
        this.timerId = 0;
    },

    onTimer : function (timerId) {
        
        this.stopWatch();
        if(!isDebugEvalEnabled()){
            return;
        }

        if(!form.Открыта()){
            this.stopWatch();
            return
        }
        try {
        updateRows(rModule)
        updateRows(rParams)
        updateRows(rLocal)
        updateRows(rHands);
        
        } catch (e) {
             // Все ошибки будем гасить
        }
    }
    
}); // end of TimerExpressionUpdater class

    return new TimerExpressionUpdater();
}