From 6a616b27e85a8c3eaee0e13aeaabfa70e133e96c Mon Sep 17 00:00:00 2001 From: Sergey Kalinin Date: Wed, 8 Apr 2026 16:47:43 +0300 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=B0=20=D0=BE=D0=B1=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D0=BA?= =?UTF-8?q?=D0=B0=20=D1=82=D1=8D=D0=B3=D0=BE=D0=B2=20=D0=B2=D1=8B=D0=B4?= =?UTF-8?q?=D0=B5=D0=BE=D0=BB=D0=B5=D0=BD=D0=B8=D1=8F=20=D1=82=D0=B5=D0=BA?= =?UTF-8?q?=D1=81=D1=82=D0=B0=20=D0=BA=D1=83=D1=80=D1=81=D0=B8=D0=B2=D0=BE?= =?UTF-8?q?=D0=BC=20=D0=B8=D0=BB=D0=B8=20=D1=82=D0=BE=D0=B4=D1=89=D0=B8?= =?UTF-8?q?=D0=BD=D0=BE=D0=B9.=20=D0=A0=D0=B5=D0=BB=D0=B8=D0=B7=D0=BE?= =?UTF-8?q?=D0=B2=D0=B0=D0=BD=D0=B0=20=D0=BE=D0=B1=D1=80=D0=B0=D0=B1=D0=BE?= =?UTF-8?q?=D1=82=D0=BA=D0=B0=20=D0=BF=D0=BE=D0=BA=D0=B0=D0=B7=D0=B0=20?= =?UTF-8?q?=D1=81=D1=81=D1=8B=D0=BB=D0=BE=D0=BA=20=D0=B8=20=D0=B2=D1=8B?= =?UTF-8?q?=D0=B7=D0=BE=D0=B2=D0=B0=20=D0=B1=D1=80=D1=83=D0=B7=D0=B5=D1=80?= =?UTF-8?q?=D0=B0=20=D0=BF=D1=80=D0=B8=20=D1=89=D0=B5=D0=BB=D1=87=D0=BA?= =?UTF-8?q?=D0=B5=20=D0=BD=D0=B0=20=D1=81=D1=81=D1=8B=D0=BB=D0=BA=D0=B5.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 8 +- lib/mdviewer.tcl | 191 ++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 186 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index bf51af7..e564be9 100644 --- a/README.md +++ b/README.md @@ -160,6 +160,7 @@ Or type "projman" into terminal, Or choose the name of the program "Projman" on - 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. @@ -186,9 +187,8 @@ shortCut= ## Credits Sergey Kalinin - author -svk@nuk-svk.ru -http://nuk-svk.ru + +Home page: [nuk-svk.ru](https://nuk-svk.ru). E-mail: [svk@nuk-svk.ru](svk@nuk-svk.ru) Laurent Riesterer - VisualREGEXP and TkDIFF+ parts -laurent.riesterer@free.fr -http://laurent.riesterer.free.fr +laurent.riesterer@free.fr [http://laurent.riesterer.free.fr](http://laurent.riesterer.free.fr) diff --git a/lib/mdviewer.tcl b/lib/mdviewer.tcl index 839338e..c45ef29 100644 --- a/lib/mdviewer.tcl +++ b/lib/mdviewer.tcl @@ -40,7 +40,7 @@ proc ShowMD {fileFullPath} { pack $frm -expand 1 -fill both set txt [text $frm.txt -wrap $cfgVariables(editorWrap) -background $cfgVariables(textBG) \ - -xscrollcommand "$win.h set" -yscrollcommand "$frm.v set"] + -xscrollcommand "$win.h set" -yscrollcommand "$frm.v set" -font $cfgVariables(viewerFont)] pack $txt -side left -expand 1 -fill both pack [ttk::scrollbar $frm.v -command "$frm.txt yview"] -side right -fill y ttk::scrollbar $win.h -orient horizontal -command "$frm.txt xview" @@ -59,6 +59,10 @@ proc ShowMD {fileFullPath} { $txt tag configure mdList -font $cfgVariables(mdListFont) $txt tag configure codeBlock -foreground $cfgVariables(codeBlockFG) \ -background $cfgVariables(codeBlockBG) -font $cfgVariables(codeBlockFont) + $txt tag configure italic -font $cfgVariables(italicFont) + $txt tag configure bold -font $cfgVariables(boldFont) + $txt tag configure italicBold -font $cfgVariables(italicBoldFont) + $txt tag configure link -foreground $cfgVariables(linkFG) -font $cfgVariables(linkFont) set codeBlockBegin false @@ -91,7 +95,13 @@ proc ShowMD {fileFullPath} { } elseif {$textTag eq "codeBlockOneString"} { ProcessLineWithCode $line $txt } elseif {$textTag eq "mdList"} { - $txt insert end " $cfgVariables(listSymbol) $result\n" + $txt insert end " $cfgVariables(listSymbol) [lindex $result 1]\n" + } elseif {$textTag eq "breakTheLine"} { + $txt insert end "[lindex $result 1]\n\n" + } elseif {$textTag eq "link"} { + ProcessLineWithURL $line $txt $result + } elseif {$textTag eq "markable"} { + ProcessLineWithMark $line $txt $result } else { $txt insert end "[lindex $result 1]\n" $textTag } @@ -101,7 +111,7 @@ proc ShowMD {fileFullPath} { } proc ProcessLineWithCode {line txt} { - set codeBlocks [ExtractCodeBlocks $line] + set codeBlocks [ExtractCodeBlocks $line {`{1,3}([^`]+)`{1,3}}] if {[llength $codeBlocks] == 0} { $txt insert end "$line\n" @@ -122,8 +132,8 @@ proc ProcessLineWithCode {line txt} { # Вставляем текст перед кодом if {$start > $lastPos} { - set text_before [string range $line $lastPos [expr {$start - 1}]] - $txt insert end $text_before + set textBefore [string range $line $lastPos [expr {$start - 1}]] + $txt insert end $textBefore } # Вставляем код с соответствующим тегом @@ -144,13 +154,108 @@ proc ProcessLineWithCode {line txt} { $txt insert end "\n" } +# Функция вставки ссылки +proc InsertLink {txt link url} { + global cfgVariables + set tag [format "link_%d" [incr ::link_counter]] + $txt insert end $link $tag + $txt tag configure $tag -foreground $cfgVariables(linkFG) -font $cfgVariables(linkFont) + $txt tag bind $tag [list OpenURL $url] + # $txt tag bind $tag [list $txt configure -cursor hand2] + $txt tag bind $tag [list InsertLinkEnter $txt $tag $url] + $txt tag bind $tag [list InsertLinkLeave $txt] + # $txt tag bind $tag [list InsertLinkLeave $txt $tag] + # $txt tag bind $tag [list %W tag configure $tag -foreground red] + # $txt tag bind $tag [list %W tag configure $tag -foreground blue] +} + +proc InsertLinkEnter {txt tag url} { + $txt configure -cursor hand2 + # Показываем подсказку с URL + ShowTooltip $txt $url +} + +proc InsertLinkLeave {txt} { + if [winfo exists .baloonTip] {destroy .baloonTip} + $txt configure -cursor "" +} + +proc ProcessLineWithURL {line txt urlList} { + if {[llength $urlList] == 0} { + $txt insert end "$line\n" + return + } + set resultLine "" + set lastPos 0 + foreach url [lindex $urlList 1] { + set start [lindex [lindex $url 1] 0] + set end [lindex [lindex $url 1] 1] + set linkName [lindex [lindex $url 2] 0] + # set linkStart [lindex [lindex $url 2] 1] + # set linkEnd [lindex [lindex $url 2] 2] + set urlName [lindex [lindex $url 3] 0] + # set urlStart [lindex [lindex $url 3] 1] + # set urlEnd [lindex [lindex $url 3] 2] + # Вставляем текст перед ссылкой + if {$start > $lastPos} { + set textBefore [string range $line $lastPos [expr {$start - 1}]] + $txt insert end $textBefore + } + # $txt insert end $linkName link + InsertLink $txt $linkName $urlName + set lastPos [expr {$end + 1}] + } + + # Вставляем остаток строки + if {$lastPos < [string length $line]} { + $txt insert end [string range $line $lastPos end] + } + + $txt insert end "\n" +} + +proc ProcessLineWithMark {line txt textList} { + if {[llength $textList] == 0} { + $txt insert end "$line\n" + return + } + set resultLine "" + set lastPos 0 + foreach record [lindex $textList 1] { + set start [lindex [lindex $record 2] 0] + set end [lindex [lindex $record 2] 1] + set markableText [lindex $record 1] + + # Вставляем текст перед ссылкой + if {$start > $lastPos} { + set textBefore [string range $line $lastPos [expr {$start - 1}]] + $txt insert end $textBefore + } + switch [lindex $record 4] { + "*" {set tag italic} + "**" {set tag bold} + "***" {set tag italicBold} + "_" {set tag italic} + "__" {set tag bold} + "___" {set tag italicBold} + } + $txt insert end " $markableText" $tag + set lastPos [expr {$end + 1}] + } + + # Вставляем остаток строки + if {$lastPos < [string length $line]} { + $txt insert end [string range $line $lastPos end] + } + + $txt insert end "\n" +} proc MarkDownParser {line} { # Title # [regexp -nocase -line -- {^(#{1,6})\s\w+} $line match sharp] if [regexp -nocase -all -line -- {^(#{1,6})\s(.+)} $line match sharp title] { set titlePrefixLength [string length $sharp] - puts $title switch $titlePrefixLength { 1 {return [list h1 "$title"]} 2 {return [list h2 "$title"]} @@ -175,18 +280,32 @@ proc MarkDownParser {line} { if [regexp -nocase -all -line -- {`{1,3}([^`]+)`{1,3}} $line match v1 code v2] { # puts $line - set result [ExtractCodeBlocks $line] + set result [ExtractCodeBlocks $line {`{1,3}([^`]+)`{1,3}}] # puts "$v1, $code, $v2" # puts "$result" return [list codeBlockOneString $result] } + # Line break (\,
, " ") + if [regexp -nocase -all -line -linestop -- {(.*)(\B|
| {2,})$} $line match v1 v2] { + return [list breakTheLine $v1] + } + # Italic text + if [regexp -nocase -all -line -linestop -- {(^|\s+)(_{1,3}|\*{1,3})([^_\*]+)(_{1,3}|\*{1,3})} $line match v1 v2 v3 v4] { + set result [ExtractBlocks $line {(^|\s+)(_{1,3}|\*{1,3})([^_\*]+)(_{1,3}|\*{1,3})}] + return [list markable $result] + } + # URL (link) parser + if [regexp -nocase -all -line -linestop -- {\[([^\]]+)\]\(([^)]+)\)} $line match v1 v2] { + set result [ExtractURL $line {\[([^\]]+)\]\(([^)]+)\)}] + return [list link $result] + } return [list {} $line] } -proc ExtractCodeBlocks {line} { - set pattern {`{1,3}([^`]+)`{1,3}} +proc ExtractCodeBlocks {line pattern} { + # set pattern {`{1,3}([^`]+)`{1,3}} set result {} # Ищем все вхождения @@ -207,7 +326,61 @@ proc ExtractCodeBlocks {line} { set pos [expr {$end + 1}] } + return $result +} + +proc ExtractURL {line pattern} { + set result {} + + # Ищем все вхождения + set pos 0 + while {[regexp -indices -start $pos -- $pattern $line match link url]} { + set start [lindex $match 0] + set end [lindex $match 1] + set linkStart [lindex $link 0] + set linkEnd [lindex $link 1] + set urlStart [lindex $url 0] + set urlEnd [lindex $url 1] + + # Получаем текст ссылки без кавычек + set linkText [string range $line $linkStart $linkEnd] + # Получаем текст url без кавычек + set urlText [string range $line $urlStart $urlEnd] + + # Получаем полный текст с кавычками + set fullMatch [string range $line $start $end] + + lappend result [list $fullMatch [list $start $end] [list $linkText $linkStart $linkEnd] [list $urlText $urlStart $urlEnd]] + + set pos [expr {$end + 1}] + } return $result } +proc ExtractBlocks {line pattern} { + set result {} + + # Ищем все вхождения + set pos 0 + while {[regexp -indices -start $pos -- $pattern $line match v1 blockSymbolBegin code blocSymbolEnd]} { + set start [lindex $match 0] + set end [lindex $match 1] + set codeStart [lindex $code 0] + set codeEnd [lindex $code 1] + + # Получаем текст кода без кавычек + set codeText [string range $line $codeStart $codeEnd] + + # Получаем полный текст с кавычками + set fullMatch [string range $line $start $end] + + lappend result [list $fullMatch $codeText [list $start $end] [list $codeStart $codeEnd] [string range $line [lindex $blockSymbolBegin 0] [lindex $blockSymbolBegin 1]]] + + set pos [expr {$end + 1}] + } + return $result +} + + +