$engine JScript
$dname Выбор типа в подсказке о параметрах
$addin stdlib
$addin global
$addin stdcommands
global.connectGlobals(SelfScript)
stdlib.require("SelectValueDialog.js", SelfScript);
/* (c) Александр Орефков
* Скрипт содержит макрос, позволяющий при наличии в подсказке о параметрах нескольких методов
* быстро выбрать нужный по типу, к которому относится метод.
* Естественно, раз быстрый выбор, то требует для работы svcsvc.dll
*/
function macrosВыбратьТипПараметра()
{
var paramPos = snegopat.paramsPosition()
if(paramPos) // Подсказка видна
{
var types = new VBArray(snegopat.paramsTypes()).toArray()
if(types.length > 1)
{
var useSvcsvc = true;
try{
var sel = new ActiveXObject('Svcsvc.Service')
}catch(e)
{
//Message("Не удалось создать объект 'Svcsvc.Service'. Зарегистрируйте svcsvc.dll")
useSvcsvc=false;
}
if(useSvcsvc){
var choice = sel.FilterValue(types.join("\r\n"), 1 | 8, '', paramPos.beginCol + 10, paramPos.beginRow + 20, paramPos.endCol - paramPos.beginCol - 20);
} else {
var dlg = new SelectValueDialog("Выбор типа в подсказке о параметрах", types);
dlg.form.GreedySearch = true;
sel = dlg.selectValue();
var choice = '';
if (sel){
choice = dlg.selectedValue;
}
}
if(choice.length)
{
for(var k in types)
{
if(types[k] == choice)
break
}
return snegopat.setParamType(k)
}
}
}
return false;
}
function getPredefinedHotkeys(predef)
{
predef.setVersion(3)
predef.add("ВыбратьТипПараметра", "Ctrl + 2")
}
//////////////////////////////////////////////////////////////////////////
// Работа по изменению списка подсказки
events.connect(snegopat, "onShowParams", SelfScript.self)
function onShowParams(p)
{
// Если текст перед методом заканчивается точкой, обработаем методы объектов
// иначе глобальные методы
(p.src.match(/\.\s*$/) ? processObjectMethod : processGlobalMethod)(p, snegopat.activeTextWindow());
//debugger
/*
Message("Запрос подсказки для метода " + p.name)
Message("Текст перед методом: " + p.src)
Message("Снегопат нашел подсказок: " + p.typesCount)
// Перебор подсказок
for(var i = 0; i < p.typesCount; i++)
Message("Подсказка № " + i + " Тип: " + p.typeName(i) + (p.typeIsModule(i) ? " Это метод из модуля" : ""))
// Удаление подсказки. Например удалим последнюю
if(p.typesCount > 1)
p.remove(p.typesCount - 1)
// Перемещение подсказки. Например, переставим последнюю в начало
if(p.typesCount > 1)
p.move(p.typesCount - 1, 0)
// Добавим свою подсказку
p.insert(0, p.name, "ИмяТипаИзКоторогоМетод", "Тут описание метода", "ВозвращаемыйТип", false)
// Добавим описания параметров к этой подсказке
p.addParamDescr(0, "Парам1", "Описание параметра 1")
p.addParamDescr(0, "Парам2", "Описание параметра 2")
*/
}
// Класс для получения названий типов объекта матаданных, т.к. штатный объект ОписаниеТипов в
// режиме Конфигуратора не выдает типы, основанные на метаданных.
function TypeFinder(mdContainer)
{
var types = new VBArray(mdContainer.typeList('', 1)).toArray()
for(var i in types)
this[types[i].clsid] = types[i].name
}
TypeFinder.prototype.getTypeString = function(mdObj)
{
var text = []
var types = new VBArray(mdObj.types()).toArray()
for(var i in types)
text.push(this[types[i]]);
return text.join(", ")
}
var clsid2typestr = new TypeFinder(metadata.current);
function processGlobalMethod(p, wnd)
{
if(p.typesCount > 1)
{
// Подсказок больше 1, надо попробовать удалить лишние
// Составим список типов, которые можно вызывать как глобальные в этом модуле
var reStr = "^ГлобальныйКонтекст$|^ВстроенныеФункцииЯзыка$"
if(wnd.mdObj)
{
var propName = wnd.mdProp.name(1)
if(propName == "Форма") // В обычной форме можно напрямую обращаться к основному реквизиту формы
{
var typesOfMainAttr
if(tov8value(wnd.mdObj.property("ТипФормы")).presentation() == 'Обычная')
{
reStr += '|^Форма$'
typesOfMainAttr = findFatFormMainAttr(wnd.extObject)
if(typesOfMainAttr)
{
// Получили массив с guid'ами типов основного реквизита
for(var k in typesOfMainAttr)
{
var tf = clsid2typestr
if(wnd.mdObj.container != metadata.current)
tf = new TypeFinder(wnd.mdObj.container)
var typeName = tf[typesOfMainAttr[k]]
if(typeName)
reStr += '|^' + typeName.replace(/\..+/, "\\.<.*") + "$"
}
}
}
else
reStr += '|^УправляемаяФорма$'
}
else if(propName == "МодульОбъекта")
{
// Здесь можно напрямую обращаться к соответствующим типам метаданных
reStr += "|^" + wnd.mdObj.mdclass.name(1) + "Объект\\.<.*$"
}
else if(propName == "МодульМенеджера")
reStr += "|^" + wnd.mdObj.mdclass.name(1) + "Менеджер\\.<.*$"
}
// Теперь обработаем список подсказок
// Проход 1 - ищем, попадает ли что-то под наш список
//Message(reStr)
var re = new RegExp(reStr, 'i')
for(var i = 0, c = p.typesCount; i < c; i++)
{
if(!p.typeIsModule(i) && re.test(p.typeName(i)))
break
}
// Если ничего не попало, оставляем, как есть, иначе удаляем все, что не попадает в наш список типов
if(i < c) // что-то совпало
{
for(i = 0; i < c; )
{
if(!p.typeIsModule(i) && !re.test(p.typeName(i)) ) // Если тип не подходит под регэксп, удалим его
{
p.remove(i)
c--
}
else
i++
}
}
}
}
function processObjectMethod(p, wnd)
{
// Пока тут мало что умеем, но хотя бы удалим методы глобального контекста
// и встроенные методы. По крайней мере для .Сообщить будет правильно показывать
if(p.typesCount > 1)
{
// Подсказок больше 1, надо попробовать удалить лишние
// Составим список типов, которые можно вызывать как глобальные в этом модуле
var reStr = "^ГлобальныйКонтекст$|^ВстроенныеФункцииЯзыка$"
var re = new RegExp(reStr, 'i')
for(var i = 0, c = p.typesCount; i < c; )
{
if(re.test(p.typeName(i)))
{
p.remove(i)
c--
}
else
i++
}
}
}
function replaceXMLsymbols(text)
{
return text.replace("&", "&").replace("<", "<").replace(">", ">")
}
// Функция преобразует стандартный 1Совский список (который с {,}) в xml
// Ибо в xml потом ковырятся с XPath гораздо проще
function list1CtoXml(text)
{
var res = []
var re = /\{|\}|,|(?:"[^"]*")+|#[^\,\}]*|[^\{\}\,\n"]+/g
while(re.exec(text))
{
switch(RegExp.lastMatch) {
case '{': // Начинаем список
res.push('<l>')
break;
case '}': // Закрываем список
res.push('</l>')
break;
case ',': // Просто разделитель списка, пропускаем, не нужен
break
default: // Значения
if(RegExp.lastMatch.length)
res.push('<e>' + replaceXMLsymbols(RegExp.lastMatch) + '</e>')
else
res.push('<e/>')
}
}
//return res.join('')
return res.join('\n')
}
function createDOM(xml)
{
var readxml = v8New('ЧтениеXML');
readxml.УстановитьСтроку(xml);
return v8New('ПостроительDOM').Прочитать(readxml)
}
function fatFormToXML(form)
{
var text = ЗначениеВСтрокуВнутр(form), xml = list1CtoXml(text)
return {text: text, xml: xml, dom: createDOM(xml)}
}
function extractTypesFromMainAttr(dom, xpathBuild)
{
var result = []
try{
var nsResolver = v8New('РазыменовательПространствИменDOM', dom);
// Получим выражение xpath
var xpath = xpathBuild(dom, nsResolver)
var defAttrTypesIt = dom.ВычислитьВыражениеXPath(xpath, dom, nsResolver, ТипРезультатаDOMXPath.УпорядоченныйИтераторУзлов)
// переберем полученные узлы
for(;;) {
var node = defAttrTypesIt.ПолучитьСледующий()
if(!node)
break
if(node.ИмяУзла == 'e' && node.ТекстовоеСодержимое != '"#"')
result.push('{' + node.ТекстовоеСодержимое.toUpperCase() + '}') // Добавим guid типа в список
}
}catch(e){}
return result
}
function findFatFormMainAttr(form)
{
//debugger
// Преобразуем форму из 1Сго списка в xml, ибо его анализировать проще
var form = fatFormToXML(form)
//Message(form.xml)
return extractTypesFromMainAttr(form.dom, function(dom, ns) {
var defAttrID = dom.ВычислитьВыражениеXPath("/l[1]/l[1]/l[2]/l[1]/e[1]", dom, ns,
ТипРезультатаDOMXPath.ПервыйУпорядоченныйУзел).ОдиночныйУзелЗначение.ТекстовоеСодержимое
return '/l[1]/l[1]/l[2]/l[2]/l[l[1]/e[1][.="' + defAttrID + '"]]/l[2]/l[1]/*'
})
}
// Это извлечение типов основного реквизита управляемой формы. Пока не используется,
// но на будущее возможно пригодится.
function managedFormToXML(mdObj, mdProp)
{
var file = mdObj.getExtProp(mdProp.id).saveToFile()
file.seek(3, fsBegin) // Первые три байта - BOM
var text = file.getString(dsUtf8), xml = list1CtoXml(text)
return {text: text, xml: xml, dom: createDOM(xml)}
}
function findMangedFormMainAttr(wnd)
{
var form = managedFormToXML(wnd.mdObj, wnd.mdProp)
return extractTypesFromMainAttr(form.dom, function(){return '/l/l[2]/l[*[18][.="1"]]/*[9]/l[1]/*'})
}