summaryrefslogtreecommitdiff
path: root/tkread
blob: 3d703f304b695c87170567c42a63e7d84ed14a80 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
#!/usr/bin/tclsh
# Usage: tkread [-w] [-m]
#        -w rewrap lines
#        -m format markdown text
#
# The markdown parsing is inspired by the code of smu:
# <https://github.com/Gottox/smu> 
#
# TODO:
# - justify text (not simple; see http://wiki.tcl.tk/1774)
# - add a basic search function
# - add function to type 30g to scroll 30% through an article
# - if window width is small, reduce padx space
# - make scrolling using mouse work even when text area isn't hovered over (also note this sort of scrolling doesn't update the title); integrate the MouseWheel event with scroll. this *should* also fix the issue of dragging and then leaving the window, as the strange scrolling is likely caused by related default behaviour
# - add more markdown processing

set fontfamily {Linux Libertine O}
set fontsize 16
set textcolour #443322
set bgcolour #eeeee2
set outercolour #222222
set inverttextcolour #eeeeee
set invertbgcolour #333030
set invertoutercolour #222222

set inverted 0
set drag 0
set tagnum 0
set domarkdown 0

set surroundfmt { \
      {"***" "0" "bold italic"} \
      {"**" "0" "bold"} \
      {"*" "0" "italic"} \
      {"===" "0" "italic"} \
      {"==" "3" "italic"} \
      {"=" "6" ""} \
     }

package require Tk

proc rewrap {text} {
	set wrapped [regsub -all {\n([^\n])} $text { \1}]
	set spaced [regsub -all {  *} $wrapped { }]
	set better [regsub -all {\n *} $spaced "\n"]
	set better [regsub -all {\n} $better "\n\n"]
	return [regsub -all {\n\n\n} $better "\n"]
}

# This uses marks before tags, as they handle deletions fine, so
# marks can be made and then the formatting characters can be
# deleted without affecting the position for formatting.
proc markup {widget} {
	global surroundfmt
	global fontfamily
	global fontsize
	global tagnum

	foreach fmt $surroundfmt {
		set searchchar [lindex $fmt 0]
		set fmtsizemod [lindex $fmt 1]
		set fmtstring [lindex $fmt 2]
		set searchlen [string length $searchchar]
		set insection 0
		set cur ""
		set markonnum 0
		set markoffnum 0

		set cur [$widget search $searchchar 0.0 end]
		while {$cur != ""} {
			if {$insection == 0} {
				set insection 1
				$widget mark set markon_$markonnum $cur
				incr markonnum
			} else {
				set insection 0
				$widget mark set markoff_$markoffnum $cur
				incr markoffnum
			}
			$widget delete $cur "$cur + $searchlen chars"

			set cur [$widget search "$searchchar" $cur end]
		}

		# ignore any final mismatched mark
		if {$markonnum != $markoffnum } {
			set markonnum $markoffnum
		}

		for {set x 0} {$x < $markonnum} {incr x} {
			$widget tag add tag_$tagnum markon_$x markoff_$x
		}

		# TODO: change in changeFontSize too if this works
		$widget tag configure tag_$tagnum -font "{$fontfamily} [expr $fontsize + $fmtsizemod] $fmtstring"
		incr tagnum
	}
}

proc changeFontSize {change} {
	global fontfamily
	global fontsize
	global surroundfmt
	global tagnum
	set newsize [expr $fontsize $change]
	if {$newsize > 0} {
		set fontsize $newsize
		.t configure -font "{$fontfamily} $fontsize" -padx [expr $fontsize * 3]
		for {set x 0} {$x < $tagnum} {incr x} {
			set fmtstring [lindex [lindex $surroundfmt $x] 2]
			set fmtsizemod [lindex [lindex $surroundfmt $x] 1]
			.t tag configure tag_$x -font "{$fontfamily} [expr $fontsize + $fmtsizemod] $fmtstring"
		}
	}
}

proc invertColours {} {
	global inverted
	global bgcolour textcolour outercolour
	global invertbgcolour inverttextcolour invertoutercolour
	if {$inverted} {
		set inverted 0
		.t configure -bg $bgcolour -fg $textcolour
		. configure -bg $outercolour
	} else {
		set inverted 1
		.t configure -bg $invertbgcolour -fg $inverttextcolour
		. configure -bg $invertoutercolour
	}
}

proc scroll {dir amount} {
	.t yview scroll $dir $amount
	set percent [expr [lindex [.t yview] 1] * 100]
	set rough [regsub {\..*} $percent {}]
	wm title . "tkread $rough%"
}

proc doMotion {ypos} {
	global lasty
	if { $lasty != -1 } {
		scroll [expr $lasty - $ypos] pixels
	}
	set lasty $ypos
}

if { [lsearch [font families] "$fontfamily"] == -1 } {
	# A font called "Times" is guaranteed by Tk to be available
	set fontfamily Times
}
. configure -bg $outercolour
text .t -font "{$fontfamily} $fontsize" -wrap word -width 64 -padx [expr $fontsize * 3] -bg $bgcolour -fg $textcolour -relief flat -inactiveselectbackground {} -cursor {}
pack .t -expand yes -fill y
set text [read stdin]
foreach arg $::argv {
	switch $arg {
		-w { set text [rewrap $text] }
		-m { set domarkdown 1 }
	}
}
.t insert end $text
if { $domarkdown } {
	markup .t
}
.t configure -state disabled ;# disable cursor

bind . <Up> {scroll -1 unit}
bind . <k> {scroll -1 unit}
bind . <Down> {scroll 1 unit}
bind . <j> {scroll 1 unit}
bind . <Prior> {scroll -1 page}
bind . <Shift-space> {scroll -1 page}
bind . <Left> {scroll -1 page}
bind . <b> {scroll -1 page}
bind . <K> {scroll -1 page}
bind . <Next> {scroll 1 page}
bind . <space> {scroll 1 page}
bind . <Right> {scroll 1 page}
bind . <J> {scroll 1 page}
bind . <Home> {.t yview moveto 0}
bind . <End> {.t yview moveto 1}
bind . <equal> {changeFontSize +5}
bind . <minus> {changeFontSize -5}
bind . <plus> {changeFontSize +1}
bind . <underscore> {changeFontSize -1}
bind . <v> {invertColours}
bind . <q> {exit}
bind . <ButtonPress-1> {set drag 1; set lasty -1}
bind . <ButtonRelease-1> {set drag 0}
bind . <Motion> {if {$drag} { doMotion %y } }