$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);
global.connectGlobals(SelfScript);
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 curMdObject = "";
var curSyntaxAnalysis = null;
var needTestModified = false;
var timerExpressionUpdater = null;
function onDebugEvent(eventID, eventParam)
{
if(eventID == "{FE7C6DDD-7C99-42F8-BA14-CDD3XEDF2EF1}")
{
form.Open() // Покажем окно
}
else if(eventID == "{71501A9D-CD34-427D-81B6-562491BEF945}")
{
clearExpressions();
timerExpressionUpdater.stopWatch();
}
if(eventID == "{5B5F928D-DF2D-4804-B2D0-B453163A2C4C}")
{
if(eventParam == 37 || eventParam == 24 ) // Остановились в точке останова
{
needTestModified = true
fillLocalVariables() // Заполним локальные переменные
//events.connect(Designer, "onIdle", SelfScript.self) // Будем их обновлять
form.Открыть();
timerExpressionUpdater.updateTimer();
}
}
//Message("eventID:"+eventID+" eventParam:"+eventParam);
}
SelfScript.self["macrosОткрыть окно отладки"] = function()
{
form.Open() // Покажем окно
}
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();
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 (title != curMdObject)
curSyntaxAnalysis = null;
curMdObject = title;
}
}
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)
{
var t = row.Название
for(var k = row.Уровень(); k > 1; k--)
{
row = row.Родитель
t = row.Название + "." + t
}
return t
}
function ПеременныеОтладкиВыбор(Элемент, ВыбраннаяСтрока, Колонка, СтандартнаяОбработка)
{
//Message('ПеременныеОтладкиВыбор');
var value = ВыбраннаяСтрока.val.Значение
if(value.indexOf('\n') >= 0)
{
Message("Значение '" + fullName(ВыбраннаяСтрока.val) + "':", mInfo)
Message(value)
}
}
var colorRed = v8new("Цвет", 255, 0, 0), colorGray = v8new("Цвет", 200, 200, 200)
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.ЭлементыФормы.ПеременныеОтладки.ТекущаяСтрока, "");
}
////////////////////////////////////////////////////////////////////////////////////////
////{ TimerExpressionUpdater - переодически обновляем значения переменных
////
TimerExpressionUpdater = stdlib.Class.extend({
construct : function() {
this.timerId = 0;
//this.startWatch();
},
updateTimer: function(){
this.stopWatch();
this.startWatch()
},
startWatch : function () {
if (this.timerId)
this.stopWatch();
this.timerId = createTimer(100, 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
//} TimerExpressionUpdater
timerExpressionUpdater = new TimerExpressionUpdater();