Не рекомендуется составлять скрипты для биндингов из строк. Говорят, делай
[list ::nsp::myproc $arg1 $arg2]
А мне нужно привязать биндинг, который сначала что-то вызывает, а потом возвращает break. Как поступить? Если я вставлю в список точку с запятой, ничего не выйдет же.
Ну а как же мне (начинающему) отличить «лишнее» попадание в quoting hell от «заслуженного»? Пытаюсь использовать только безопасные варианты. Тут вроде в твоём коде придраться не к чему, хотя, честно сказать, я не могу сказать, что на 100% уложил в голове правила «квотинга». Ну и байт-компилятор - тоже цель достойная.
Твой код у меня в таком виде более-менее заработал
# Так нормально
set cmd [concat [list tk_messageBox -message "hello"] ";" break]
# А если это раскомментарить, то проскочит и в следующий обработчик
# set cmd [concat [list tk_messageBox -message "hello"]]
text .t
.t insert 1.0 $cmd
pack .t
bind . <F3> "tk_messageBox -message {:(}"
bind .t <F3> $cmd
Ладно, в общем, ясно, что ничего не ясно. Во всяком случае, свою локальную задачу я почему-то решил. Нужная мне функция сама уже возвращает -code break. Эксперимент показал, что всё сработало правильно, хотя у меня нет уверенности, что я правильно понял, как оно работает. Едем дальше :)
Для этого решения нужно осилить доку по команде bind, на это пока нет сил. Иначе не вижу гарантии, почему break сработает после, а не до [list procedure ... ]
Мне больше всего нравится вариант, предложенный buddhist-ом и доработанный мной.
Я соглашусь, что придумать что-то самостоятельно интереснее, чем читать документацию. Но скорее всего и времени отнимет больше. Плюсик перед скриптом именно что добавляет скрипт в конец к уже привязанным, так что сработать «до» у него мало шансов.
set cmd [concat [list tk_messageBox -message "hello"] ";" break]
вообще не нужно динамически формировать строку. Тут обычный статичный код, не содержащий переменных или вложенных команд, поэтому его можно сразу же записать в фигурных скобках. Пример:
Вообще там, как правило, бывает имя окна. Но я просто в целом пытаюсь понять, как обходиться со сгенерированным кодом, поскольку вариант «сгенерируй замыкание и выполни его после ответа с сервера» - постоянно встречающаяся ситуация. Вот и думаю, можно ли тут list-ом обойтись.
Красота — понятие субъективное. Не нравится, не делай. Что же касается «более, чем одного биндинга», то так не бывает. Одному событию для одного тега может соответствовать не более одного биндинга:
Выведенные две строки это один двустрочный скрипт. А break нужен для того, чтобы скрипты, прибинденные к другим тегам для того же события, не выполнялись (я убежден, что ты это и так знаешь, но вдруг еще кто-нибудь прочитает):
То, что ты предлагаешь, является допустимым решением. Но биндинги - это частность. Я в целом не понимаю, как правильно генерить замыкания в tcl и пока к пониманию не особо приблизился, хотя в моём приложении опробовал несколько вариантов. После лиспа все они выглядят лагерной баландой, кроме самого красивого, который, как я понял, ведёт в кавычечный ад. Вот такого:
Здесь генерируемый код визуально похож именно на код и не нужны эти ужасные обратные кавычки в конце строки. Был, правда, ещё вариант с лямбдами, но там ЕМНИП не получалось сделать, чтобы выглядело как код и при этом чтобы это было замыкание, т.е. чтобы часть подстановок сделать в момент генерации кода.
Поэтому мой конкретный вопрос про биндинги - это лишь повод для более общего вопроса. Вариант с +break - в этом плане не общий и не является ответом на основной вопрос.
Вот я кстати наутро проснулся и понял, что от кавычечного ада в некоторой степени защитит следование правилам:
1. Не допускать значений по умолчанию для аргументов функции. Именованные аргументы должны быть отдельным обязательным аргументом - списком.
2. Избегать передачу пустой строки в качестве «лжи». Использовать вместо этого ноль.
К сожалению, сами команды tcl первое правило мало когда выполняют, имеют множество необязательных ключей, да ещё и следующих в разном порядке. Кроме того, есть риск перепутать ключ и данные. Так что это похоже на недостаток tcl, который никак не обойти.