diff --git a/.gitea/workflows/build.yml b/.gitea/workflows/build.yml index d84f269..95acb18 100644 --- a/.gitea/workflows/build.yml +++ b/.gitea/workflows/build.yml @@ -1,54 +1,269 @@ -name: Gitea Actions Demo -run-name: ${{ gitea.actor }} is testing out Gitea Actions 🚀 -on: [push] +name: Build and Release +on: + push: + branches: + - master + - main + workflow_dispatch: # Ручной запуск jobs: - Explore-Gitea-Actions: + build: runs-on: tcl-tk-builder steps: - - name: Build the DEB-packages + - name: Клонирование run: | - git clone ${{ vars.main_url }}${{ gitea.repository }} - pwd - cd projman/debian - ./build-deb-projman.sh - cd ../openbsd - ./build-package-bsd.sh - cd ../../ - curl --user ${{secrets.USER}}:${{secrets.API_TOKEN}} --upload-file "$(ls -1| grep projman | grep -E 'deb$')" ${{vars.main_url}}api/packages/${{vars.user}}/debian/pool/bookworm/main/upload - - run: echo "This job's status is ${{ job.status }}." - - - name: Create release - run: | - # Создаем релиз через API - curl -X POST \ - -u "${{ secrets.USER }}:${{ secrets.API_TOKEN }}" \ - -H "Content-Type: application/json" \ - -d '{ - "tag_name": "'"${{ gitea.ref_name }}"'", - "name": "Release '"${{ gitea.ref_name }}"'", - "body": "Automated release for '"${{ gitea.ref_name }}"'", - "draft": false, - "prerelease": false - }' \ - "${{vars.main_url}}/api/v1/repos/${{ gitea.repository }}/releases" - - - name: Get release ID - id: release_info - run: | - response=$(curl -s -u "${{ secrets.USER }}:${{ secrets.API_TOKEN }}" \ - "${{vars.main_url}}/api/v1/repos/${{ gitea.repository }}/releases/tags/${{ gitea.ref_name }}") + git clone "${{ vars.main_url }}${{ gitea.repository }}.git" . - echo "id=$(echo $response | jq -r '.id')" >> $GITHUB_OUTPUT - - - name: Upload Linux package + - name: Получение версии + id: get_version run: | - curl --user "${{ secrets.USER }}:${{ secrets.API_TOKEN }}" \ - --upload-file "$(ls -1| grep projman | grep -E 'deb$')" \ - "${{vars.main_url}}/api/v1/repos/${{ gitea.repository }}/releases/${{ steps.release_info.outputs.id }}/assets?name=$(ls -1| grep projman | grep -E 'deb$')" + VERSION=$(grep "Version" projman.tcl | head -1 | grep -o '[0-9.]\+[a-zA-Z0-9]*' || echo "1.0.0") + RELEASE=$(grep "# Release" projman.tcl | tail -1 | awk '{print $NF}' || echo "$(date +%Y%m%d)") + + # Создаем имя тега + TAG="v${VERSION}" + echo "TAG=$TAG" >> $GITEA_ENV + echo "VERSION=$VERSION" >> $GITEA_ENV + echo "RELEASE=$RELEASE" >> $GITEA_ENV + + echo "Тег: $TAG" + echo "Версия: $VERSION" + echo "Ревизия: $RELEASE" - - name: Upload OpenBSD package + - name: Проверка существования тега + id: check_tag run: | - curl --user "${{ secrets.USER }}:${{ secrets.API_TOKEN }}" \ - --upload-file "$(ls -1| grep projman | grep -E 'tgz$')" \ - "${{vars.main_url}}/api/v1/repos/${{ gitea.repository }}/releases/${{ steps.release_info.outputs.id }}/assets?name=$(ls -1| grep projman | grep -E 'tgz$')" + echo "Проверяем тег: $TAG" + + # Проверяем на удаленном сервере + if git ls-remote --tags origin "$TAG" 2>/dev/null | grep -q "$TAG"; then + echo "Тег $TAG уже существует на удаленном сервере" + echo "TAG_EXISTS_REMOTE=true" >> $GITEA_ENV + else + echo "Тег $TAG не существует на удаленном сервере" + echo "TAG_EXISTS_REMOTE=false" >> $GITEA_ENV + fi + + - name: Создание тега (только если не существует) + if: env.TAG_EXISTS_REMOTE == 'false' + run: | + echo "Создаем новый тег: $TAG" + git config user.email "svk@nuk-svk.ru" + git config user.name "svk" + + # Создаем тег локально + git tag -a "$TAG" -m "Release $TAG - $RELEASE" + + # Настраиваем URL для push + git remote set-url origin "https://${{ secrets.USER }}:${{ secrets.API_TOKEN }}@git.nuk-svk.ru/${{ gitea.repository }}.git" + + # Пушим тег на сервер + git push origin "$TAG" + + - name: Сборка пакетов + run: | + echo "=== Сборка DEB пакета ===" + cd debian && ./build-deb-projman.sh + + echo "=== Сборка OpenBSD пакета ===" + cd ../openbsd && ./build-package-bsd.sh + + echo "=== Собранные файлы ===" + find . -maxdepth 1 -name "projman*" -type f | xargs ls -la 2>/dev/null || echo "Файлы не найдены" + + - name: Проверка существования релиза + id: check_release + run: | + # Проверяем, существует ли уже релиз для этого тега + RESPONSE=$(curl -s -u "${{ secrets.USER }}:${{ secrets.API_TOKEN }}" \ + "${{ vars.main_url }}api/v1/repos/${{ gitea.repository }}/releases/tags/$TAG" || echo "{}") + + echo "Ответ API проверки релиза: $RESPONSE" + + # Извлекаем id релиза - первый id в JSON + if echo "$RESPONSE" | grep -q '"id"'; then + # Извлекаем только первый id (id релиза), игнорируем id автора + # Используем awk для точного извлечения + REL_ID=$(echo "$RESPONSE" | awk -F'"id":' '{print $2}' | awk -F',' '{print $1}' | head -1 | tr -d ' ') + echo "Релиз уже существует. ID: $REL_ID" + echo "RELEASE_EXISTS=true" >> $GITEA_ENV + + # Очищаем и сохраняем REL_ID в файл + echo -n "$REL_ID" | tr -d '\n' > /tmp/rel_id.txt + else + echo "Релиз не существует" + echo "RELEASE_EXISTS=false" >> $GITEA_ENV + echo -n "" > /tmp/rel_id.txt + fi + + - name: Создание или обновление релиза + id: create_release + run: | + # Читаем REL_ID из файла и очищаем от лишних символов + REL_ID=$(cat /tmp/rel_id.txt 2>/dev/null | tr -d '\n\r ' || echo "") + + echo "=== Работа с релизом для тега $TAG ===" + echo "RELEASE_EXISTS: $RELEASE_EXISTS" + echo "REL_ID: '$REL_ID'" + + RELEASE_BODY="## Projman $VERSION + + **Ревизия:** $RELEASE + **Дата сборки:** $(date) + **Коммит:** $(git rev-parse --short HEAD)" + + + # Экранируем переносы строк для JSON + ESCAPED_BODY=$(echo "$RELEASE_BODY" | sed ':a;N;$!ba;s/\n/\\n/g') + + if [ "$RELEASE_EXISTS" = "true" ] && [ -n "$REL_ID" ]; then + echo "Обновляем существующий релиз ID: $REL_ID" + + # Обновляем существующий релиз + RESPONSE=$(curl -s -X PATCH \ + -u "${{ secrets.USER }}:${{ secrets.API_TOKEN }}" \ + -H "Content-Type: application/json" \ + -d '{ + "name": "Projman '"$VERSION"'", + "body": "'"$ESCAPED_BODY"'", + "draft": false, + "prerelease": false + }' \ + "${{ vars.main_url }}api/v1/repos/${{ gitea.repository }}/releases/$REL_ID") + + echo "Ответ обновления релиза: $RESPONSE" + + # Проверяем ответ + if echo "$RESPONSE" | grep -q '"id"'; then + echo "Релиз успешно обновлен" + else + echo "ОШИБКА: Не удалось обновить релиз" + echo "Ответ: $RESPONSE" + exit 1 + fi + + else + echo "Создаем новый релиз" + + # Создаем новый релиз + RESPONSE=$(curl -s -X POST \ + -u "${{ secrets.USER }}:${{ secrets.API_TOKEN }}" \ + -H "Content-Type: application/json" \ + -d '{ + "tag_name": "'"$TAG"'", + "name": "Projman '"$VERSION"'", + "body": "'"$ESCAPED_BODY"'", + "draft": false, + "prerelease": false + }' \ + "${{ vars.main_url }}api/v1/repos/${{ gitea.repository }}/releases") + + echo "Ответ создания релиза: $RESPONSE" + + # Получаем ID нового релиза + NEW_REL_ID=$(echo "$RESPONSE" | awk -F'"id":' '{print $2}' | awk -F',' '{print $1}' | head -1 | tr -d ' ') + if [ -n "$NEW_REL_ID" ]; then + echo "Новый ID релиза: $NEW_REL_ID" + echo -n "$NEW_REL_ID" > /tmp/rel_id.txt + else + echo "ОШИБКА: Не удалось получить ID релиза из ответа" + echo "Ответ: $RESPONSE" + echo -n "" > /tmp/rel_id.txt + exit 1 + fi + fi + + - name: Загрузка файлов в релиз + run: | + # Читаем REL_ID из файла и очищаем + REL_ID=$(cat /tmp/rel_id.txt 2>/dev/null | tr -d '\n\r ' || echo "") + + if [ -z "$REL_ID" ]; then + echo "Нет ID релиза, пропускаем загрузку файлов" + exit 0 + fi + + echo "=== Загрузка файлов в релиз ===" + echo "ID релиза для загрузки: $REL_ID" + + # Находим все файлы projman + FILES=$(find ../ -maxdepth 1 \( -name "*projman*deb" -o -name "*projman*tgz" \) -type f) + if [ -z "$FILES" ]; then + echo "Нет файлов projman для загрузки" + exit 0 + fi + + echo "Найдены файлы:" + echo "$FILES" + + # Сначала проверим существующие ассеты + echo "=== Проверяем существующие ассеты ===" + curl -s -u "${{ secrets.USER }}:${{ secrets.API_TOKEN }}" \ + "${{ vars.main_url }}api/v1/repos/${{ gitea.repository }}/releases/$REL_ID/assets" | \ + jq -r '.[].name' 2>/dev/null || echo "Не удалось получить список ассетов" + + # Загружаем каждый файл + for FILE in $FILES; do + FILENAME=$(basename "$FILE") + echo "Загружаем: $FILENAME" + + # Используем правильный endpoint для загрузки ассетов + UPLOAD_URL="${{ vars.main_url }}api/v1/repos/${{ gitea.repository }}/releases/$REL_ID/assets" + + echo "URL загрузки: $UPLOAD_URL?name=$FILENAME" + + # Загружаем файл + RESPONSE=$(curl -s -w "\nHTTP_STATUS:%{http_code}" \ + --user "${{ secrets.USER }}:${{ secrets.API_TOKEN }}" \ + -H "Content-Type: application/octet-stream" \ + -X POST \ + --data-binary @"$FILE" \ + "$UPLOAD_URL?name=$FILENAME") + + HTTP_STATUS=$(echo "$RESPONSE" | grep "HTTP_STATUS:" | cut -d':' -f2) + API_RESPONSE=$(echo "$RESPONSE" | grep -v "HTTP_STATUS:") + + echo "Статус: $HTTP_STATUS" + echo "Ответ API: $API_RESPONSE" + + if [ "$HTTP_STATUS" = "201" ] || [ "$HTTP_STATUS" = "200" ]; then + echo "✅ Файл загружен: $FILENAME" + else + echo "❌ ОШИБКА загрузки: $FILENAME" + echo "Детали: $API_RESPONSE" + fi + + echo "---" + done + + # Проверяем итоговый список ассетов + echo "=== Итоговый список ассетов ===" + curl -s -u "${{ secrets.USER }}:${{ secrets.API_TOKEN }}" \ + "${{ vars.main_url }}api/v1/repos/${{ gitea.repository }}/releases/$REL_ID/assets" | \ + jq -r '.[] | "\(.name) - \(.browser_download_url)"' 2>/dev/null || \ + curl -s -u "${{ secrets.USER }}:${{ secrets.API_TOKEN }}" \ + "${{ vars.main_url }}api/v1/repos/${{ gitea.repository }}/releases/$REL_ID/assets" | \ + grep -o '"name":"[^"]*"' | cut -d'"' -f4 + + - name: Финализация + run: | + # Читаем REL_ID из файла + REL_ID=$(cat /tmp/rel_id.txt 2>/dev/null | tr -d '\n\r ' || echo "") + + echo "=== Сборка завершена ===" + echo "Тег: $TAG" + echo "Версия: $VERSION" + echo "Ревизия: $RELEASE" + echo "ID релиза: $REL_ID" + + if [ -n "$REL_ID" ]; then + echo "Проверяем файлы в релизе..." + curl -s -u "${{ secrets.USER }}:${{ secrets.API_TOKEN }}" \ + "${{ vars.main_url }}api/v1/repos/${{ gitea.repository }}/releases/$REL_ID/assets" | \ + grep -o '"name":"[^"]*"' | cut -d'"' -f4 || echo "Не удалось получить список файлов" + else + echo "Релиз не был создан или ID не получен" + fi + + echo "Собранные файлы:" + find ../ -maxdepth 1 \( -name "*projman*deb" -o -name "*projman*tgz" \) -type f | xargs ls -la 2>/dev/null || echo "Файлы не найдены" diff --git a/README.md b/README.md index bacf2bc..62c1e53 100644 --- a/README.md +++ b/README.md @@ -158,6 +158,29 @@ Or type "projman" into terminal, Or choose the name of the program "Projman" on - Alt-S - Split the edited window horizontally - Alt-K - Open folder +### Work with external tools +ProjMan allows you to connect any external tools to the editor. To do this, you need to add an entry to the file ~/.config/projman/tools.ini. + +Calling an external program is available through the main and pop-up menus. To transfer the parameters, write the appropriate template in the file. + - %s - template for substituting selected text in the editor + - %f - template for substituting selected file\(s\) in the file tree + +When adding multiple %f templates, the corresponding number of files allocated in the tree will be substituted. + +``` +[TkDIFF] +commandString=tkdiff %f %f +description=TkDiff is a Tcl/Tk front-end to diff +icon= +shortCut= + +[VisualRegexp] +commandString=tkregexp "%s" +description=A graphical front-end to write/debug regular expression +icon= +shortCut= +``` + ## Credits Sergey Kalinin - author diff --git a/debian/build-deb-projman.sh b/debian/build-deb-projman.sh index d332154..0cb4911 100755 --- a/debian/build-deb-projman.sh +++ b/debian/build-deb-projman.sh @@ -11,6 +11,7 @@ sed -i "/# Build:.*/c$TXT" projman.tcl cp projman.tcl projman cp changelog-gen.tcl changelog-gen +cp tkregexp.tcl tkregexp ./changelog-gen.tcl --project-name projman --project-version ${VERSION} --project-release ${RELEASE} --out-file debian/changelog --deb --last @@ -25,5 +26,5 @@ dpkg-buildpackage -d #cp ../projman_${VERSION}-${RELEASE}_amd64.deb /files/ -rm -v projman changelog-gen +rm -v projman changelog-gen tkregexp rm -r -v debian/{projman,.debhelper} diff --git a/debian/changelog b/debian/changelog index 52aad62..a7f1d13 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,19 @@ +projman (2.0.0-beta2) stable; urgency=medium + + * Добавлено подключение (bind) сочетания клавиш указанных в настройках инструментов. + * Добавлена динамическая генерация меню 'Инструменты'. Теперь новые внешние инструменты доступны сразу после сохранения файла настроек tools.ini в редакторе. + * Исправлена ошибка с некорректным определением виджета в процедуре получения выделенного текста. + * Добавлено редактирование настроек внешних инструментов. И пункт в меню 'Инструменты'->'Настройки' + * Исправление ошибки с запуском внешних программ. + * Добавлено определение путей до внешних программ при подключении к редактору. + * Сделана обработка шаблонов командной строки и запуск внешних инструментов. + * Добавлен tkregexp для установки в /usr/bin + * Начало работы с внешними инструментами: - Добавлено создание и работа (проверка параметров + * Исправлен скрипт сборки бсд-пакета + * Добавлена сборка пакетов для openbsd + + -- svk Tue, 27 Jan 2026 16:44:48 +0300 + projman (2.0.0-beta1) stable; urgency=medium * Сделан вывод отладочной информации по запросу. @@ -468,3 +484,5 @@ projman (2.0.0-alfa0) stable; urgency=medium + + diff --git a/debian/install b/debian/install index 954b959..621a7cb 100644 --- a/debian/install +++ b/debian/install @@ -1,5 +1,6 @@ projman /usr/bin/ changelog-gen /usr/bin/ +tkregexp /usr/bin lib/*.tcl /usr/share/projman/lib lib/msgs/* /usr/share/projman/lib/msgs theme /usr/share/projman/ diff --git a/lib/editor.tcl b/lib/editor.tcl index 7e585ee..4c727c8 100644 --- a/lib/editor.tcl +++ b/lib/editor.tcl @@ -363,15 +363,24 @@ namespace eval Editor { } } - proc SelectionGet {txt} { - variable selectionText + proc SelectionGet {{txt ""}} { + global nbEditor + variable selectionText "" + if {$txt eq ""} { + DebugPuts "Editor::SelectionGet: [focus]" + set txt [focus] + if {![string match -nocase "*text*" $txt]} { + return "" + } + } set selBegin [lindex [$txt tag ranges sel] 0] set selEnd [lindex [$txt tag ranges sel] 1] if {$selBegin ne "" && $selEnd ne ""} { set selectionText [$txt get $selBegin $selEnd] } + return $selectionText } - + proc SelectionHighlight {txt} { variable selectionText $txt tag remove lightSelected 1.0 end diff --git a/lib/files.tcl b/lib/files.tcl index fe4383b..df4cdb3 100644 --- a/lib/files.tcl +++ b/lib/files.tcl @@ -391,6 +391,12 @@ namespace eval FileOper { if {[file tail $filePath] eq "projman.ini"} { Config::read $dir(cfg) } + if {[file tail $filePath] eq "tools.ini"} { + Tools::Read $dir(cfg) + Tools::CheckVariables + Tools::GetMenu .popup.tools + Tools::GetMenu .frmMenu.mnuTools.m + } if [string match "*untitled*" $nbEditorItem] { FileOper::Close if {$type ne "close"} { diff --git a/lib/gui.tcl b/lib/gui.tcl index 3f26659..d5f0a8f 100644 --- a/lib/gui.tcl +++ b/lib/gui.tcl @@ -135,7 +135,11 @@ GetEditMenu [menu .frmMenu.mnuEdit.m] ttk::menubutton .frmMenu.mnuView -text [::msgcat::mc "View"] -menu .frmMenu.mnuView.m GetViewMenu [menu .frmMenu.mnuView.m] -pack .frmMenu.mnuFile .frmMenu.mnuEdit .frmMenu.mnuView -side left +ttk::menubutton .frmMenu.mnuTools -text [::msgcat::mc "Tools"] -menu .frmMenu.mnuTools.m +Tools::GetMenu [menu .frmMenu.mnuTools.m] + + +pack .frmMenu.mnuFile .frmMenu.mnuEdit .frmMenu.mnuView .frmMenu.mnuTools -side left ttk::menubutton .frmMenu.mnuHelp -text [::msgcat::mc "Help"] -menu .frmMenu.mnuHelp.m GetHelpMenu [menu .frmMenu.mnuHelp.m] @@ -151,6 +155,9 @@ GetFileMenu .popup.file menu .popup.view .popup add cascade -label [::msgcat::mc "View"] -menu .popup.view GetViewMenu .popup.view +menu .popup.tools +.popup add cascade -label [::msgcat::mc "Tools"] -menu .popup.tools +Tools::GetMenu .popup.tools set frmTool [ttk::frame .frmBody.frmTool] ttk::panedwindow .frmBody.panel -orient horizontal -style TPanedwindow diff --git a/lib/msgs/en.msg b/lib/msgs/en.msg index 1840432..72cadfe 100644 --- a/lib/msgs/en.msg +++ b/lib/msgs/en.msg @@ -174,6 +174,7 @@ ::msgcat::mcset en "Title normal" ::msgcat::mcset en "Title modify" ::msgcat::mcset en "Toolbar" +::msgcat::mcset en "Tools" ::msgcat::mcset en "Undo" ::msgcat::mcset en "Update" ::msgcat::mcset en "Variables" @@ -185,4 +186,3 @@ ::msgcat::mcset en "Work dir" - diff --git a/lib/msgs/ru.msg b/lib/msgs/ru.msg index bff7471..0991f34 100644 --- a/lib/msgs/ru.msg +++ b/lib/msgs/ru.msg @@ -214,6 +214,7 @@ ::msgcat::mcset ru "Title normal" "Файл нормальный" ::msgcat::mcset ru "Title modify" "Файл изменен" ::msgcat::mcset ru "Toolbar" "Панель инструментов" +::msgcat::mcset ru "Tools" "Инструменты" ::msgcat::mcset ru "User name" "Имя пользователя" ::msgcat::mcset ru "Undo" "Отменить" ::msgcat::mcset ru "Update" "Обновить" diff --git a/lib/tools.tcl b/lib/tools.tcl new file mode 100644 index 0000000..0051bff --- /dev/null +++ b/lib/tools.tcl @@ -0,0 +1,220 @@ +################################################################## +# tools.tcl - this file implements the logic of working +# with external tools. +################################################################## +# svk, 01/2026 +################################################################## + +namespace eval Tools {} { + variable toolsINISections + variable toolsVariables +} + +set ::toolsDefault "\[VisualRegexp\] +commandString=tkregexp \"%s\" +description=A graphical front-end to write/debug regular expression +icon= +shortCut= +\[TkDIFF\] +commandString=tkdiff %f %f +description=TkDiff is a Tcl/Tk front-end to diff +icon= +shortCut= +" +# Создание файла настроек внешних инструментов +proc Tools::Create {dir} { + set toolsFile [open [file join $dir tools.ini] "w+"] + puts $toolsFile $::toolsDefault + close $toolsFile +} + +proc Tools::Read {dir} { + set ::toolsVariables "" + set toolsFile [ini::open [file join $dir tools.ini] "r"] + foreach section [ini::sections $toolsFile] { + foreach key [ini::keys $toolsFile $section] { + lappend ::toolsINIsections($section) $key + dict set ::toolsVariables $section $key [ini::value $toolsFile $section $key] + DebugPuts "Tools::Read: $toolsFile $section $key = [ini::value $toolsFile $section $key]" + } + } + ini::close $toolsFile +} + +proc Tools::Write {dir} { + set toolsFile [ini::open [file join $dir tools.ini] "w"] + foreach section [array names ::toolsINIsections] { + dict for {key value} [dict get $::toolsVariables $section] { + DebugPuts "Tools::write: $section $key = $value" + # ini::set $toolsFile $section $key [dict get $::toolsVariables $section $key] + ini::set $toolsFile $section $key $value + } + } + ini::commit $toolsFile + ini::close $toolsFile +} + +# Добавление перменной в список +# если отсутствует нужная секция то она будет добавлена. +proc Tools::AddVariable {key value section} { + # Проверяем, существует ли уже такая переменная + if {[info exists ::toolsVariables($key)]} { + DebugPuts "The variable '$key' already exists: " + return 0 + } + # Добавляем в массив переменных + # set ::toolsVariables($key) $value + dict set ::toolsVariables $section $key $value + # Добавляем в список ключей секции + if {[dict exists $::toolsVariables $key]} { + # Проверяем, нет ли уже такого ключа в секции + if {[lsearch -exact $::toolsINIsections($section) $key] == -1} { + lappend ::toolsINIsections($section) $key + } + } else { + set ::toolsINIsections($section) [list $key] + } + DebugPuts "Tools::AddVariable: The variable '$key' has been added to the '$section' array 'toolsVariables' with value '$value'" + + return 1 +} + +# Проверяем наличие переменных в tools.ini на основе "эталонного" списка +# и выставляем значение по умолчанию если в конфиге переменной нет +proc Tools::CheckVariables {} { + set valList [split $::toolsDefault "\n"] + foreach item $valList { + if {[regexp -nocase -all -- {\[(\w+)\]} $item -> v1]} { + set section $v1 + } + if {[regexp {^([^=]+)=(.*)$} $item -> key value]} { + # puts "$section $key $value >> [dict get $::toolsVariables $section $key]" + # if {[dict get $::toolsVariables $section $key] eq ""} + if ![dict exists $::toolsVariables $section $key] { + DebugPuts "Error in Tools::CheckVariables: variable $section $key not found" + Tools::AddVariable "$key" "$value" "$section" + # DebugPuts "Tools::CheckVariables: The variable toolsVariables $key setting to default value \"$value\"" + } + } + } + foreach id [dict keys $::toolsVariables] { + DebugPuts "Tools::CheckVariables: config parameters for $id [dict get $::toolsVariables $id]!" + } + # DebugPuts "toolsVariables dict keys: [dict keys $::toolsVariables]" +} + +proc Tools::GetMenu {m} { + global cfgVariables toolsVariables + set count [$m index end] + if {$count != "none"} { + for {set i $count} {$i >= 0} {incr i -1} { + $m delete $i + } + } + foreach toolName [dict keys $toolsVariables] { + dict for {key value} [dict get $toolsVariables $toolName] { + DebugPuts "GetToolsMenu $key $value" + if {$key eq "commandString"} { + set cmd "$value" + } + if {$key eq "shortCut"} { + set shortCut "$value" + } + } + if {[info exists cmd] == 1 && $cmd ne ""} { + if {[info exists shortCut] == 1 && $shortCut ne ""} { + $m add command -label $toolName -accelerator $shortCut -command [list Tools::Execute "$toolName"] + bind . <$shortCut> "[list Tools::Execute "$toolName"]; break" + } else { + $m add command -label $toolName -command [list Tools::Execute "$toolName"] + } + } + } + $m add separator + $m add command -label "[::msgcat::mc "Settings"]" -command Tools::Settings +} + +proc Tools::CommandPathSettings {command} { + global tcl_platform + if [file exists $command] {return $command} + + if {$tcl_platform(platform) eq "windows"} { + set cmd "where $command)" + } else { + set cmd "which $command" + } + DebugPuts [catch {exec {*}$cmd} toolsPath] + DebugPuts "executor_path $toolsPath" + if {[catch {exec {*}$cmd} toolsPath]} { + DebugPuts "Tools::CommandPathSettings: Программа $command не найдена в системе" + return "" + } + set fullPath [string trim $toolsPath] + set firstPath [lindex [split $toolsPath "\n"] 0] + + DebugPuts "Tools::CommandPathSettings: executable path $fullPath" + return $fullPath +} + +proc Tools::Execute {toolName} { + global cfgVariables toolsVariables tree + if ![dict exists $::toolsVariables $toolName commandString] { + DebugPuts "Tools::Execute: command for $toolName not found" + return + } else { + set command [dict get $::toolsVariables $toolName commandString] + DebugPuts "Tools::Execute: command for $toolName as $command" + } + # 7. Проверять команды на доступность в системе и подставлять полный путь к команде + # если в конфиге не указан полный путь. + # Проверем наличие внешгних программ в системе + set cmd [lindex [split $command " "] 0] + if [file exists $cmd] { + set fullCommand $command + } else { + set fullPathToExec [Tools::CommandPathSettings "$cmd"] + set fullCommand [lreplace [split $command " "] 0 0 $fullPathToExec] + } + if {$fullPathToExec eq ""} { + DebugPuts "Tools::Execute: $command not found" + return + } else { + DebugPuts "Tools::Execute: $fullPathToExec, $fullCommand" + } + # 2. Определять выделен ли текст в открытом редакторе + # 5. Заменяем %s на выделенный в редакторе текст + set selectedText [Editor::SelectionGet] + if {$selectedText ne ""} { + regsub -all "%s" $fullCommand "$selectedText" fullCommand + DebugPuts "Tools::Execute: selected text \"$selectedText\", command \"$fullCommand\"" + } + + # 1. Определять текущий файл + # 3. Опеределять сколько файлов выделено в дереве + # 4. Заменяем знак %f на имя текущего файла (файлов) + # regsub -all "%f" $command "$filePath" fullCommand + set filesList [Tree::GetSelectedItemValues $tree] + if {$filesList ne ""} { + foreach file $filesList { + # Если больше нет %f для замены, выходим из цикла + if {![string match "*%f*" $fullCommand]} break + set fullCommand [regsub {%f} $fullCommand $file] + } + } + + # 6. Заменяем %d на текущий каталог(и), если он выделен в дереве, + # и если не выделено то корневой открытый в дереве + DebugPuts "Tools::Execute: $fullCommand" + + set pipe [open "|$fullCommand" "r"] + fileevent $pipe readable + fconfigure $pipe -buffering none -blocking no +} + +# Правка файла настроек +proc Tools::Settings {} { + global dir + + FileOper::Edit [file join $dir(cfg) tools.ini] + # Config::read $dir(cfg) +} diff --git a/lib/tree.tcl b/lib/tree.tcl index 920c63a..2fc99ab 100644 --- a/lib/tree.tcl +++ b/lib/tree.tcl @@ -99,6 +99,7 @@ namespace eval Tree { proc PressItem {tree} { global nbEditor lexers editors activeProject set id [$tree selection] + if {[llength $id] > 1} {return} $tree tag remove selected $tree item $id -tags selected SetActiveProject [GetItemID $tree [GetUpperItem $tree $id]] @@ -160,5 +161,12 @@ namespace eval Tree { GetUpperItem $tree $parent } } - + + proc GetSelectedItemValues {tree} { + set valuesList "" + foreach itemID [$tree selection] { + lappend valuesList [GetItemID $tree $itemID] + } + return $valuesList + } } diff --git a/openbsd/build-package-bsd.sh b/openbsd/build-package-bsd.sh index 7f32f8d..78c1f95 100755 --- a/openbsd/build-package-bsd.sh +++ b/openbsd/build-package-bsd.sh @@ -49,7 +49,6 @@ cat > ${WORK_DIR}/${PKG_FULLNAME}/+CONTENTS << EOF @depend devel/tklib:tklib-*:tcl-* @comment Editor for Tcl/Tk and other languages. @arch amd64 -@wantlib pthread @ignore @cwd /usr/local EOF @@ -78,7 +77,7 @@ Supported languages for highlighting and navigation: Tcl/Tk, GO, Perl, Python, Ruby, Shell (BASH), Markdown, YAML (Ansible), Lua. EOF -(cd ${WORK_DIR} && tar -czf ../../../${PKG_FULLNAME}.tgz ${PKG_FULLNAME}/) +(cd ${WORK_DIR}/${PKG_FULLNAME}/ && pwd && ls -1 && tar -czf ../../../../${PKG_FULLNAME}.tgz .) echo "Package created: ${PKG_FULLNAME}.tgz" diff --git a/projman.tcl b/projman.tcl index 18ad1ef..ccd279f 100755 --- a/projman.tcl +++ b/projman.tcl @@ -9,8 +9,8 @@ exec wish8.6 "$0" -- "$@" # Home page: https://nuk-svk.ru ###################################################### # Version: 2.0.0 -# Release: beta1 -# Build: 22012026174911 +# Release: beta2 +# Build: 28012026124210 ###################################################### # определим текущую версию, релиз и т.д. @@ -114,13 +114,22 @@ foreach modFile [lsort [glob -nocomplain [file join $dir(theme) *]]] { } -# загружаем пользовательский конфиг, если он отсутствует, то копируем дефолтный -if {[file exists [file join $dir(cfg) projman.ini]] ==0} { +# загружаем пользовательский конфиг, если он отсутствует или пустой, то копируем дефолтный +if {[file exists [file join $dir(cfg) projman.ini]] == 0 || [file size [file join $dir(cfg) projman.ini]] == 0} { Config::create $dir(cfg) } Config::read $dir(cfg) Config::CheckVariables +# загружаем пользовательский конфиг для инстурментов, если он отсутствует или пустой, то копируем дефолтный +if {[file exists [file join $dir(cfg) tools.ini]] == 0 || [file size [file join $dir(cfg) tools.ini]] == 0} { + Tools::Create $dir(cfg) +} +# Читаем настройки для внешних инструментов +Tools::Read $dir(cfg) +Tools::CheckVariables +Tools::Write $dir(cfg) + ::msgcat::mclocale $cfgVariables(locale) if [::msgcat::mcload [file join $dir(lib) msgs]] {