sekka 0.8.2 → 0.8.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/COPYING CHANGED
@@ -43,7 +43,7 @@ Copyright and condition of use of main portion of the source:
43
43
 
44
44
  Copyright of emacs/*.el ---------------------------------------------------
45
45
 
46
- This file is covered by GPL version 2
46
+ This file is covered by GPL version 2 or 3
47
47
 
48
48
  Copyright of data/SKK-JISYO.* -----------------------------------------------
49
49
 
@@ -4,6 +4,7 @@
4
4
  require 'digest/md5'
5
5
  require 'fileutils'
6
6
  require 'rack'
7
+ require 'uri'
7
8
  require File.expand_path(File.dirname(__FILE__) + "/../lib/sekkaconfig")
8
9
  require File.expand_path(File.dirname(__FILE__) + "/../lib/sekka/sekkaversion")
9
10
 
@@ -12,6 +13,8 @@ require File.expand_path(File.dirname(__FILE__) + "/../lib/sekka/sekkaversion")
12
13
  DICTDIR = File.expand_path( "~/.sekka-server" )
13
14
  DICTURL = "http://sumibi.org/sekka/dict/" + SekkaVersion.version
14
15
 
16
+ PIDFILE = DICTDIR + "/pid"
17
+
15
18
  TC_FILE = DICTDIR + "/SEKKA-JISYO.SMALL.tch"
16
19
  SUMFILE = DICTDIR + "/SEKKA-JISYO.SMALL.md5"
17
20
  TC_URL = DICTURL + "/SEKKA-JISYO.SMALL.tch"
@@ -30,6 +33,20 @@ def main
30
33
  STDERR.printf( "Info: created directory [%s]\n", DICTDIR )
31
34
  end
32
35
 
36
+ # sekka-server自身のpidを書きこむ(デーモン化したときの停止用)
37
+ open( PIDFILE, "w" ) {|f|
38
+ f.printf( "%d\n", Process.pid )
39
+ }
40
+
41
+ # 環境変数からHTTPプロキシサーバーの情報を取得する
42
+ proxyHost = nil
43
+ proxyPort = nil
44
+ if ENV.key?( 'http_proxy' )
45
+ uri = URI.parse ENV[ 'http_proxy' ]
46
+ proxyPort = uri.port
47
+ proxyHost = uri.host
48
+ end
49
+
33
50
  if not File.exist?( TC_FILE )
34
51
  STDERR.printf( "Info: Downloading SEKKA-JISYO\n" )
35
52
  # 辞書をダウンロードする
@@ -64,7 +81,7 @@ def main
64
81
  list = TC_FILE_LIST.select { |name| File.exist?( name ) }
65
82
 
66
83
  # 設定項目をConfigオブジェクトに代入
67
- SekkaServer::Config.setup( list[0], MEMCACHED, 12929 )
84
+ SekkaServer::Config.setup( list[0], MEMCACHED, 12929, proxyHost, proxyPort )
68
85
 
69
86
  # サーバースクリプトのrootディレクトリへ移動
70
87
  FileUtils.cd(File.dirname(__FILE__) + "/../")
@@ -0,0 +1,1061 @@
1
+ ;;; popup.el --- Visual popup interface
2
+
3
+ ;; Copyright (C) 2009, 2010 Tomohiro Matsuyama
4
+
5
+ ;; Author: Tomohiro Matsuyama <tomo@cx4a.org>
6
+ ;; Keywords: lisp
7
+ ;; Version: 0.4
8
+
9
+ ;; This program is free software; you can redistribute it and/or modify
10
+ ;; it under the terms of the GNU General Public License as published by
11
+ ;; the Free Software Foundation, either version 3 of the License, or
12
+ ;; (at your option) any later version.
13
+
14
+ ;; This program is distributed in the hope that it will be useful,
15
+ ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
16
+ ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
+ ;; GNU General Public License for more details.
18
+
19
+ ;; You should have received a copy of the GNU General Public License
20
+ ;; along with this program. If not, see <http://www.gnu.org/licenses/>.
21
+
22
+ ;;; Commentary:
23
+
24
+ ;;
25
+
26
+ ;;; Code:
27
+
28
+ (eval-when-compile
29
+ (require 'cl))
30
+
31
+
32
+
33
+ ;; Utilities
34
+
35
+ (defvar popup-use-optimized-column-computation t
36
+ "Use optimized column computation routine.
37
+ If there is a problem, please set it to nil.")
38
+
39
+ ;; Borrowed from anything.el
40
+ (defmacro popup-aif (test-form then-form &rest else-forms)
41
+ "Anaphoric if. Temporary variable `it' is the result of test-form."
42
+ (declare (indent 2))
43
+ `(let ((it ,test-form))
44
+ (if it ,then-form ,@else-forms)))
45
+
46
+ (defun popup-x-to-string (x)
47
+ "Convert any object to string effeciently.
48
+ This is faster than prin1-to-string in many cases."
49
+ (typecase x
50
+ (string x)
51
+ (symbol (symbol-name x))
52
+ (integer (number-to-string x))
53
+ (float (number-to-string x))
54
+ (t (format "%s" x))))
55
+
56
+ (defun popup-substring-by-width (string width)
57
+ "Return cons of substring and remaining string by `WIDTH'."
58
+ ;; Expand tabs with 4 spaces
59
+ (setq string (replace-regexp-in-string "\t" " " string))
60
+ (loop with len = (length string)
61
+ with w = 0
62
+ for l from 0
63
+ for c in (append string nil)
64
+ while (<= (incf w (char-width c)) width)
65
+ finally return
66
+ (if (< l len)
67
+ (cons (substring string 0 l) (substring string l))
68
+ (list string))))
69
+
70
+ (defun popup-fill-string (string &optional width max-width justify squeeze)
71
+ "Split STRING into fixed width strings and return a cons cell like
72
+ \(WIDTH . ROWS). Here, the car WIDTH indicates the actual maxim width of ROWS.
73
+
74
+ The argument WIDTH specifies the width of filling each paragraph. WIDTH nil
75
+ means don't perform any justification and word wrap. Note that this function
76
+ doesn't add any padding characters at the end of each row.
77
+
78
+ MAX-WIDTH, if WIDTH is nil, specifies the maximum number of columns.
79
+
80
+ The optional fourth argument JUSTIFY specifies which kind of justification
81
+ to do: `full', `left', `right', `center', or `none' (equivalent to nil).
82
+ A value of t means handle each paragraph as specified by its text properties.
83
+
84
+ SQUEEZE nil means leave whitespaces other than line breaks untouched."
85
+ (if (eq width 0)
86
+ (error "Can't fill string with 0 width"))
87
+ (if width
88
+ (setq max-width width))
89
+ (with-temp-buffer
90
+ (let ((tab-width 4)
91
+ (fill-column width)
92
+ (left-margin 0)
93
+ (kinsoku-limit 1)
94
+ indent-tabs-mode
95
+ row rows)
96
+ (insert string)
97
+ (untabify (point-min) (point-max))
98
+ (if width
99
+ (fill-region (point-min) (point-max) justify (not squeeze)))
100
+ (goto-char (point-min))
101
+ (setq width 0)
102
+ (while (prog2
103
+ (let ((line (buffer-substring
104
+ (point) (progn (end-of-line) (point)))))
105
+ (if max-width
106
+ (while (progn
107
+ (setq row (truncate-string-to-width line max-width)
108
+ width (max width (string-width row)))
109
+ (push row rows)
110
+ (if (not (= (length row) (length line)))
111
+ (setq line (substring line (length row))))))
112
+ (setq width (max width (string-width line)))
113
+ (push line rows)))
114
+ (< (point) (point-max))
115
+ (beginning-of-line 2)))
116
+ (cons width (nreverse rows)))))
117
+
118
+ (defmacro popup-save-buffer-state (&rest body)
119
+ (declare (indent 0))
120
+ `(save-excursion
121
+ (let ((buffer-undo-list t)
122
+ (buffer-read-only nil)
123
+ (modified (buffer-modified-p)))
124
+ (unwind-protect
125
+ (progn ,@body)
126
+ (set-buffer-modified-p modified)))))
127
+
128
+ (defun popup-preferred-width (list)
129
+ "Return preferred width of popup to show `LIST' beautifully."
130
+ (loop with tab-width = 4
131
+ for item in list
132
+ for summary = (popup-item-summary item)
133
+ maximize (string-width (popup-x-to-string item)) into width
134
+ if (stringp summary)
135
+ maximize (+ (string-width summary) 2) into summary-width
136
+ finally return (* (ceiling (/ (+ (or width 0) (or summary-width 0)) 10.0)) 10)))
137
+
138
+ ;; window-full-width-p is not defined in Emacs 22.1
139
+ (defun popup-window-full-width-p (&optional window)
140
+ (if (fboundp 'window-full-width-p)
141
+ (window-full-width-p window)
142
+ (= (window-width window) (frame-width (window-frame (or window (selected-window)))))))
143
+
144
+ ;; truncated-partial-width-window-p is not defined in Emacs 22
145
+ (defun popup-truncated-partial-width-window-p (&optional window)
146
+ (unless window
147
+ (setq window (selected-window)))
148
+ (unless (popup-window-full-width-p window)
149
+ (let ((t-p-w-w (buffer-local-value 'truncate-partial-width-windows
150
+ (window-buffer window))))
151
+ (if (integerp t-p-w-w)
152
+ (< (window-width window) t-p-w-w)
153
+ t-p-w-w))))
154
+
155
+ (defun popup-current-physical-column ()
156
+ (or (when (and popup-use-optimized-column-computation
157
+ (eq (window-hscroll) 0))
158
+ (let ((current-column (current-column)))
159
+ (if (or (popup-truncated-partial-width-window-p)
160
+ truncate-lines
161
+ (< current-column (window-width)))
162
+ current-column)))
163
+ (car (posn-col-row (posn-at-point)))))
164
+
165
+ (defun popup-last-line-of-buffer-p ()
166
+ (save-excursion (end-of-line) (/= (forward-line) 0)))
167
+
168
+ (defun popup-lookup-key-by-event (function event)
169
+ (or (funcall function (vector event))
170
+ (if (symbolp event)
171
+ (popup-aif (get event 'event-symbol-element-mask)
172
+ (funcall function (vector (logior (or (get (car it) 'ascii-character) 0)
173
+ (cadr it))))))))
174
+
175
+
176
+
177
+ ;; Popup common
178
+
179
+ (defgroup popup nil
180
+ "Visual popup interface"
181
+ :group 'lisp
182
+ :prefix "popup-")
183
+
184
+ (defface popup-face
185
+ '((t (:background "lightgray" :foreground "black")))
186
+ "Face for popup."
187
+ :group 'popup)
188
+
189
+ (defface popup-scroll-bar-foreground-face
190
+ '((t (:background "black")))
191
+ "Foreground face for scroll-bar."
192
+ :group 'popup)
193
+
194
+ (defface popup-scroll-bar-background-face
195
+ '((t (:background "gray")))
196
+ "Background face for scroll-bar."
197
+ :group 'popup)
198
+
199
+ (defvar popup-instances nil
200
+ "Popup instances.")
201
+
202
+ (defvar popup-scroll-bar-foreground-char
203
+ (propertize " " 'face 'popup-scroll-bar-foreground-face)
204
+ "Foreground character for scroll-bar.")
205
+
206
+ (defvar popup-scroll-bar-background-char
207
+ (propertize " " 'face 'popup-scroll-bar-background-face)
208
+ "Background character for scroll-bar.")
209
+
210
+ (defstruct popup
211
+ point row column width height min-height direction overlays
212
+ parent depth
213
+ face selection-face
214
+ margin-left margin-right margin-left-cancel scroll-bar symbol
215
+ cursor offset scroll-top current-height list newlines
216
+ pattern original-list)
217
+
218
+ (defun popup-item-propertize (item &rest properties)
219
+ "Same to `propertize` but this avoids overriding existed value with `nil` property."
220
+ (let (props)
221
+ (while properties
222
+ (when (cadr properties)
223
+ (push (car properties) props)
224
+ (push (cadr properties) props))
225
+ (setq properties (cddr properties)))
226
+ (apply 'propertize
227
+ (popup-x-to-string item)
228
+ (nreverse props))))
229
+
230
+ (defun popup-item-property (item property)
231
+ (if (stringp item)
232
+ (get-text-property 0 property item)))
233
+
234
+ (defun* popup-make-item (name
235
+ &key
236
+ value
237
+ popup-face
238
+ selection-face
239
+ sublist
240
+ document
241
+ symbol
242
+ summary)
243
+ "Utility function to make popup item.
244
+ See also `popup-item-propertize'."
245
+ (popup-item-propertize name
246
+ 'value value
247
+ 'popup-face popup-face
248
+ 'selection-face selection-face
249
+ 'document document
250
+ 'symbol symbol
251
+ 'summary summary
252
+ 'sublist sublist))
253
+
254
+ (defsubst popup-item-value (item) (popup-item-property item 'value))
255
+ (defsubst popup-item-value-or-self (item) (or (popup-item-value item) item))
256
+ (defsubst popup-item-popup-face (item) (popup-item-property item 'popup-face))
257
+ (defsubst popup-item-selection-face (item) (popup-item-property item 'selection-face))
258
+ (defsubst popup-item-document (item) (popup-item-property item 'document))
259
+ (defsubst popup-item-summary (item) (popup-item-property item 'summary))
260
+ (defsubst popup-item-symbol (item) (popup-item-property item 'symbol))
261
+ (defsubst popup-item-sublist (item) (popup-item-property item 'sublist))
262
+
263
+ (defun popup-item-documentation (item)
264
+ (let ((doc (popup-item-document item)))
265
+ (if (functionp doc)
266
+ (setq doc (funcall doc (popup-item-value-or-self item))))
267
+ doc))
268
+
269
+ (defun popup-item-show-help-1 (item)
270
+ (let ((doc (popup-item-documentation item)))
271
+ (when doc
272
+ (with-current-buffer (get-buffer-create " *Popup Help*")
273
+ (erase-buffer)
274
+ (insert doc)
275
+ (goto-char (point-min))
276
+ (display-buffer (current-buffer)))
277
+ t)))
278
+
279
+ (defun popup-item-show-help (item &optional persist)
280
+ (when item
281
+ (if (not persist)
282
+ (save-window-excursion
283
+ (when (popup-item-show-help-1 item)
284
+ (block nil
285
+ (while t
286
+ (clear-this-command-keys)
287
+ (let ((key (read-key-sequence-vector nil)))
288
+ (case (key-binding key)
289
+ ('scroll-other-window
290
+ (scroll-other-window))
291
+ ('scroll-other-window-down
292
+ (scroll-other-window-down nil))
293
+ (t
294
+ (setq unread-command-events (append key unread-command-events))
295
+ (return))))))))
296
+ (popup-item-show-help-1 item))))
297
+
298
+ (defun popup-set-list (popup list)
299
+ (popup-set-filtered-list popup list)
300
+ (setf (popup-pattern popup) nil)
301
+ (setf (popup-original-list popup) list))
302
+
303
+ (defun popup-set-filtered-list (popup list)
304
+ (setf (popup-list popup) list
305
+ (popup-offset popup) (if (> (popup-direction popup) 0)
306
+ 0
307
+ (max (- (popup-height popup) (length list)) 0))))
308
+
309
+ (defun popup-selected-item (popup)
310
+ (nth (popup-cursor popup) (popup-list popup)))
311
+
312
+ (defun popup-selected-line (popup)
313
+ (- (popup-cursor popup) (popup-scroll-top popup)))
314
+
315
+ (defun popup-line-overlay (popup line)
316
+ (aref (popup-overlays popup) line))
317
+
318
+ (defun popup-selected-line-overlay (popup)
319
+ (popup-line-overlay popup (popup-selected-line popup)))
320
+
321
+ (defun popup-hide-line (popup line)
322
+ (let ((overlay (popup-line-overlay popup line)))
323
+ (overlay-put overlay 'display nil)
324
+ (overlay-put overlay 'after-string nil)))
325
+
326
+ (defun popup-line-hidden-p (popup line)
327
+ (let ((overlay (popup-line-overlay popup line)))
328
+ (and (eq (overlay-get overlay 'display) nil)
329
+ (eq (overlay-get overlay 'after-string) nil))))
330
+
331
+ (defun popup-set-line-item (popup line item face margin-left margin-right scroll-bar-char symbol summary)
332
+ (let* ((overlay (popup-line-overlay popup line))
333
+ (content (popup-create-line-string popup (popup-x-to-string item) margin-left margin-right symbol summary))
334
+ (start 0)
335
+ (prefix (overlay-get overlay 'prefix))
336
+ (postfix (overlay-get overlay 'postfix))
337
+ end)
338
+ ;; Overlap face properties
339
+ (if (get-text-property start 'face content)
340
+ (setq start (next-single-property-change start 'face content)))
341
+ (while (and start (setq end (next-single-property-change start 'face content)))
342
+ (put-text-property start end 'face face content)
343
+ (setq start (next-single-property-change end 'face content)))
344
+ (if start
345
+ (put-text-property start (length content) 'face face content))
346
+ (unless (overlay-get overlay 'dangle)
347
+ (overlay-put overlay 'display (concat prefix (substring content 0 1)))
348
+ (setq prefix nil
349
+ content (concat (substring content 1))))
350
+ (overlay-put overlay
351
+ 'after-string
352
+ (concat prefix
353
+ content
354
+ scroll-bar-char
355
+ postfix))))
356
+
357
+ (defun popup-create-line-string (popup string margin-left margin-right symbol summary)
358
+ (let* ((popup-width (popup-width popup))
359
+ (summary-width (string-width summary))
360
+ (string (car (popup-substring-by-width string
361
+ (- popup-width
362
+ (if (> summary-width 0)
363
+ (+ summary-width 2)
364
+ 0)))))
365
+ (string-width (string-width string)))
366
+ (concat margin-left
367
+ string
368
+ (make-string (max (- popup-width string-width summary-width) 0) ? )
369
+ summary
370
+ symbol
371
+ margin-right)))
372
+
373
+ (defun popup-live-p (popup)
374
+ (and popup (popup-overlays popup) t))
375
+
376
+ (defun popup-child-point (popup &optional offset)
377
+ (overlay-end (popup-line-overlay popup
378
+ (or offset
379
+ (popup-selected-line popup)))))
380
+
381
+ (defun* popup-create (point
382
+ width
383
+ height
384
+ &key
385
+ min-height
386
+ around
387
+ (face 'popup-face)
388
+ (selection-face face)
389
+ scroll-bar
390
+ margin-left
391
+ margin-right
392
+ symbol
393
+ parent
394
+ parent-offset)
395
+ (or margin-left (setq margin-left 0))
396
+ (or margin-right (setq margin-right 0))
397
+ (unless point
398
+ (setq point
399
+ (if parent (popup-child-point parent parent-offset) (point))))
400
+
401
+ (save-excursion
402
+ (goto-char point)
403
+ (let* ((row (line-number-at-pos))
404
+ (column (popup-current-physical-column))
405
+ (overlays (make-vector height nil))
406
+ (popup-width (+ width
407
+ (if scroll-bar 1 0)
408
+ margin-left
409
+ margin-right
410
+ (if symbol 2 0)))
411
+ margin-left-cancel
412
+ (window (selected-window))
413
+ (window-start (window-start))
414
+ (window-hscroll (window-hscroll))
415
+ (window-width (window-width))
416
+ (right (+ column popup-width))
417
+ (overflow (and (> right window-width)
418
+ (>= right popup-width)))
419
+ (foldable (and (null parent)
420
+ (>= column popup-width)))
421
+ (direction (or
422
+ ;; Currently the direction of cascade popup won't be changed
423
+ (and parent (popup-direction parent))
424
+
425
+ ;; Calculate direction
426
+ (if (and (> row height)
427
+ (> height (- (max 1 (- (window-height)
428
+ (if mode-line-format 1 0)
429
+ (if header-line-format 1 0)))
430
+ (count-lines window-start (point)))))
431
+ -1
432
+ 1)))
433
+ (depth (if parent (1+ (popup-depth parent)) 0))
434
+ (newlines (max 0 (+ (- height (count-lines point (point-max))) (if around 1 0))))
435
+ current-column)
436
+ (when (> newlines 0)
437
+ (popup-save-buffer-state
438
+ (goto-char (point-max))
439
+ (insert (make-string newlines ?\n))))
440
+
441
+ (if overflow
442
+ (if foldable
443
+ (progn
444
+ (decf column (- popup-width margin-left margin-right))
445
+ (unless around (move-to-column column)))
446
+ (when (not truncate-lines)
447
+ ;; Cut out overflow
448
+ (let ((d (1+ (- popup-width (- window-width column)))))
449
+ (decf popup-width d)
450
+ (decf width d)))
451
+ (decf column margin-left))
452
+ (decf column margin-left))
453
+ (when (and (null parent)
454
+ (< column 0))
455
+ ;; Cancel margin left
456
+ (setq column 0)
457
+ (decf popup-width margin-left)
458
+ (setq margin-left-cancel t))
459
+
460
+ (dotimes (i height)
461
+ (let (overlay begin w (dangle t) (prefix "") (postfix ""))
462
+ (when around
463
+ (if (>= emacs-major-version 23)
464
+ (vertical-motion (cons column direction))
465
+ (vertical-motion direction)
466
+ (move-to-column (+ (current-column) column))))
467
+ (setq around t
468
+ current-column (popup-current-physical-column))
469
+
470
+ (when (> current-column column)
471
+ (backward-char)
472
+ (setq current-column (popup-current-physical-column)))
473
+ (when (< current-column column)
474
+ ;; Extend short buffer lines by popup prefix (line of spaces)
475
+ (setq prefix (make-string (+ (if (= current-column 0)
476
+ (- window-hscroll (current-column))
477
+ 0)
478
+ (- column current-column))
479
+ ? )))
480
+
481
+ (setq begin (point))
482
+ (setq w (+ popup-width (length prefix)))
483
+ (while (and (not (eolp)) (> w 0))
484
+ (setq dangle nil)
485
+ (decf w (char-width (char-after)))
486
+ (forward-char))
487
+ (if (< w 0)
488
+ (setq postfix (make-string (- w) ? )))
489
+
490
+ (setq overlay (make-overlay begin (point)))
491
+ (overlay-put overlay 'window window)
492
+ (overlay-put overlay 'dangle dangle)
493
+ (overlay-put overlay 'prefix prefix)
494
+ (overlay-put overlay 'postfix postfix)
495
+ (overlay-put overlay 'width width)
496
+ (aset overlays
497
+ (if (> direction 0) i (- height i 1))
498
+ overlay)))
499
+ (loop for p from (- 10000 (* depth 1000))
500
+ for overlay in (nreverse (append overlays nil))
501
+ do (overlay-put overlay 'priority p))
502
+ (let ((it (make-popup :point point
503
+ :row row
504
+ :column column
505
+ :width width
506
+ :height height
507
+ :min-height min-height
508
+ :direction direction
509
+ :parent parent
510
+ :depth depth
511
+ :face face
512
+ :selection-face selection-face
513
+ :margin-left margin-left
514
+ :margin-right margin-right
515
+ :margin-left-cancel margin-left-cancel
516
+ :scroll-bar scroll-bar
517
+ :symbol symbol
518
+ :cursor 0
519
+ :scroll-top 0
520
+ :current-height 0
521
+ :list nil
522
+ :newlines newlines
523
+ :overlays overlays)))
524
+ (push it popup-instances)
525
+ it))))
526
+
527
+ (defun popup-delete (popup)
528
+ (when (popup-live-p popup)
529
+ (popup-hide popup)
530
+ (mapc 'delete-overlay (popup-overlays popup))
531
+ (setf (popup-overlays popup) nil)
532
+ (setq popup-instances (delq popup popup-instances))
533
+ (let ((newlines (popup-newlines popup)))
534
+ (when (> newlines 0)
535
+ (popup-save-buffer-state
536
+ (goto-char (point-max))
537
+ (dotimes (i newlines)
538
+ (if (= (char-before) ?\n)
539
+ (delete-char -1)))))))
540
+ nil)
541
+
542
+ (defun popup-draw (popup)
543
+ (loop with height = (popup-height popup)
544
+ with min-height = (popup-min-height popup)
545
+ with popup-face = (popup-face popup)
546
+ with selection-face = (popup-selection-face popup)
547
+ with list = (popup-list popup)
548
+ with length = (length list)
549
+ with thum-size = (max (/ (* height height) (max length 1)) 1)
550
+ with page-size = (/ (+ 0.0 (max length 1)) height)
551
+ with scroll-bar = (popup-scroll-bar popup)
552
+ with margin-left = (make-string (if (popup-margin-left-cancel popup) 0 (popup-margin-left popup)) ? )
553
+ with margin-right = (make-string (popup-margin-right popup) ? )
554
+ with symbol = (popup-symbol popup)
555
+ with cursor = (popup-cursor popup)
556
+ with scroll-top = (popup-scroll-top popup)
557
+ with offset = (popup-offset popup)
558
+ for o from offset
559
+ for i from scroll-top
560
+ while (< o height)
561
+ for item in (nthcdr scroll-top list)
562
+ for page-index = (* thum-size (/ o thum-size))
563
+ for face = (if (= i cursor)
564
+ (or (popup-item-selection-face item) selection-face)
565
+ (or (popup-item-popup-face item) popup-face))
566
+ for empty-char = (propertize " " 'face face)
567
+ for scroll-bar-char = (if scroll-bar
568
+ (cond
569
+ ((<= page-size 1)
570
+ empty-char)
571
+ ((and (> page-size 1)
572
+ (>= cursor (* page-index page-size))
573
+ (< cursor (* (+ page-index thum-size) page-size)))
574
+ popup-scroll-bar-foreground-char)
575
+ (t
576
+ popup-scroll-bar-background-char))
577
+ "")
578
+ for sym = (if symbol
579
+ (concat " " (or (popup-item-symbol item) " "))
580
+ "")
581
+ for summary = (or (popup-item-summary item) "")
582
+
583
+ do
584
+ ;; Show line and set item to the line
585
+ (popup-set-line-item popup o item face margin-left margin-right scroll-bar-char sym summary)
586
+
587
+ finally
588
+ ;; Remember current height
589
+ (setf (popup-current-height popup) (- o offset))
590
+
591
+ ;; Hide remaining lines
592
+ (let ((scroll-bar-char (if scroll-bar (propertize " " 'face popup-face) ""))
593
+ (symbol (if symbol " " "")))
594
+ (if (> (popup-direction popup) 0)
595
+ (progn
596
+ (when min-height
597
+ (while (< o min-height)
598
+ (popup-set-line-item popup o "" popup-face margin-left margin-right scroll-bar-char symbol "")
599
+ (incf o)))
600
+ (while (< o height)
601
+ (popup-hide-line popup o)
602
+ (incf o)))
603
+ (loop with h = (if min-height (- height min-height) offset)
604
+ for o from 0 below offset
605
+ if (< o h)
606
+ do (popup-hide-line popup o)
607
+ if (>= o h)
608
+ do (popup-set-line-item popup o "" popup-face margin-left margin-right scroll-bar-char symbol ""))))))
609
+
610
+ (defun popup-hide (popup)
611
+ (dotimes (i (popup-height popup))
612
+ (popup-hide-line popup i)))
613
+
614
+ (defun popup-hidden-p (popup)
615
+ (let ((hidden t))
616
+ (when (popup-live-p popup)
617
+ (dotimes (i (popup-height popup))
618
+ (unless (popup-line-hidden-p popup i)
619
+ (setq hidden nil))))
620
+ hidden))
621
+
622
+ (defun popup-select (popup i)
623
+ (setq i (+ i (popup-offset popup)))
624
+ (when (and (<= 0 i) (< i (popup-height popup)))
625
+ (setf (popup-cursor popup) i)
626
+ (popup-draw popup)
627
+ t))
628
+
629
+ (defun popup-next (popup)
630
+ (let ((height (popup-height popup))
631
+ (cursor (1+ (popup-cursor popup)))
632
+ (scroll-top (popup-scroll-top popup))
633
+ (length (length (popup-list popup))))
634
+ (cond
635
+ ((>= cursor length)
636
+ ;; Back to first page
637
+ (setq cursor 0
638
+ scroll-top 0))
639
+ ((= cursor (+ scroll-top height))
640
+ ;; Go to next page
641
+ (setq scroll-top (min (1+ scroll-top) (max (- length height) 0)))))
642
+ (setf (popup-cursor popup) cursor
643
+ (popup-scroll-top popup) scroll-top)
644
+ (popup-draw popup)))
645
+
646
+ (defun popup-previous (popup)
647
+ (let ((height (popup-height popup))
648
+ (cursor (1- (popup-cursor popup)))
649
+ (scroll-top (popup-scroll-top popup))
650
+ (length (length (popup-list popup))))
651
+ (cond
652
+ ((< cursor 0)
653
+ ;; Go to last page
654
+ (setq cursor (1- length)
655
+ scroll-top (max (- length height) 0)))
656
+ ((= cursor (1- scroll-top))
657
+ ;; Go to previous page
658
+ (decf scroll-top)))
659
+ (setf (popup-cursor popup) cursor
660
+ (popup-scroll-top popup) scroll-top)
661
+ (popup-draw popup)))
662
+
663
+ (defun popup-scroll-down (popup &optional n)
664
+ (let ((scroll-top (min (+ (popup-scroll-top popup) (or n 1))
665
+ (- (length (popup-list popup)) (popup-height popup)))))
666
+ (setf (popup-cursor popup) scroll-top
667
+ (popup-scroll-top popup) scroll-top)
668
+ (popup-draw popup)))
669
+
670
+ (defun popup-scroll-up (popup &optional n)
671
+ (let ((scroll-top (max (- (popup-scroll-top popup) (or n 1))
672
+ 0)))
673
+ (setf (popup-cursor popup) scroll-top
674
+ (popup-scroll-top popup) scroll-top)
675
+ (popup-draw popup)))
676
+
677
+
678
+
679
+ ;; Popup isearch
680
+
681
+ (defface popup-isearch-match
682
+ '((t (:background "sky blue")))
683
+ "Popup isearch match face."
684
+ :group 'popup)
685
+
686
+ (defvar popup-isearch-cursor-color "blue")
687
+
688
+ (defvar popup-isearch-keymap
689
+ (let ((map (make-sparse-keymap)))
690
+ ;(define-key map "\r" 'popup-isearch-done)
691
+ (define-key map "\C-g" 'popup-isearch-cancel)
692
+ (define-key map "\C-h" 'popup-isearch-delete)
693
+ (define-key map (kbd "DEL") 'popup-isearch-delete)
694
+ map))
695
+
696
+ (defsubst popup-isearch-char-p (char)
697
+ (and (integerp char)
698
+ (<= 32 char)
699
+ (<= char 126)))
700
+
701
+ (defun popup-isearch-filter-list (pattern list)
702
+ (loop with regexp = (regexp-quote pattern)
703
+ for item in list
704
+ do
705
+ (unless (stringp item)
706
+ (setq item (popup-item-propertize (popup-x-to-string item)
707
+ 'value item)))
708
+ if (string-match regexp item)
709
+ collect (let ((beg (match-beginning 0))
710
+ (end (match-end 0)))
711
+ (alter-text-property 0 (length item) 'face
712
+ (lambda (prop)
713
+ (unless (eq prop 'popup-isearch-match)
714
+ prop))
715
+ item)
716
+ (put-text-property beg end
717
+ 'face 'popup-isearch-match
718
+ item)
719
+ item)))
720
+
721
+ (defun popup-isearch-prompt (popup pattern)
722
+ (format "Pattern: %s" (if (= (length (popup-list popup)) 0)
723
+ (propertize pattern 'face 'isearch-fail)
724
+ pattern)))
725
+
726
+ (defun popup-isearch-update (popup pattern &optional callback)
727
+ (setf (popup-cursor popup) 0
728
+ (popup-scroll-top popup) 0
729
+ (popup-pattern popup) pattern)
730
+ (let ((list (popup-isearch-filter-list pattern (popup-original-list popup))))
731
+ (popup-set-filtered-list popup list)
732
+ (if callback
733
+ (funcall callback list)))
734
+ (popup-draw popup))
735
+
736
+ (defun* popup-isearch (popup
737
+ &key
738
+ (cursor-color popup-isearch-cursor-color)
739
+ (keymap popup-isearch-keymap)
740
+ callback
741
+ help-delay)
742
+ (let ((list (popup-original-list popup))
743
+ (pattern (or (popup-pattern popup) ""))
744
+ (old-cursor-color (frame-parameter (selected-frame) 'cursor-color))
745
+ prompt key binding done)
746
+ (unwind-protect
747
+ (unless (block nil
748
+ (if cursor-color
749
+ (set-cursor-color cursor-color))
750
+ (while t
751
+ (setq prompt (popup-isearch-prompt popup pattern))
752
+ (setq key (popup-menu-read-key-sequence keymap prompt help-delay))
753
+ (if (null key)
754
+ (unless (funcall popup-menu-show-quick-help-function popup nil :prompt prompt)
755
+ (clear-this-command-keys)
756
+ (push (read-event prompt) unread-command-events))
757
+ (setq binding (lookup-key keymap key))
758
+ (cond
759
+ ((and (stringp key)
760
+ (popup-isearch-char-p (aref key 0)))
761
+ (setq pattern (concat pattern key)))
762
+ ((eq binding 'popup-isearch-done)
763
+ (return t))
764
+ ((eq binding 'popup-isearch-cancel)
765
+ (return nil))
766
+ ((eq binding 'popup-isearch-delete)
767
+ (if (> (length pattern) 0)
768
+ (setq pattern (substring pattern 0 (1- (length pattern))))))
769
+ (t
770
+ (setq unread-command-events
771
+ (append (listify-key-sequence key) unread-command-events))
772
+ (return t)))
773
+ (popup-isearch-update popup pattern callback))))
774
+ (popup-isearch-update popup "" callback)
775
+ t) ; Return non-nil if isearch is cancelled
776
+ (if old-cursor-color
777
+ (set-cursor-color old-cursor-color)))))
778
+
779
+
780
+
781
+ ;; Popup tip
782
+
783
+ (defface popup-tip-face
784
+ '((t (:background "khaki1" :foreground "black")))
785
+ "Face for popup tip."
786
+ :group 'popup)
787
+
788
+ (defvar popup-tip-max-width 80)
789
+
790
+ (defun* popup-tip (string
791
+ &key
792
+ point
793
+ (around t)
794
+ width
795
+ (height 15)
796
+ min-height
797
+ truncate
798
+ margin
799
+ margin-left
800
+ margin-right
801
+ scroll-bar
802
+ parent
803
+ parent-offset
804
+ nowait
805
+ prompt
806
+ &aux tip lines)
807
+ (if (bufferp string)
808
+ (setq string (with-current-buffer string (buffer-string))))
809
+ ;; TODO strip text (mainly face) properties
810
+ (setq string (substring-no-properties string))
811
+
812
+ (and (eq margin t) (setq margin 1))
813
+ (or margin-left (setq margin-left margin))
814
+ (or margin-right (setq margin-right margin))
815
+
816
+ (let ((it (popup-fill-string string width popup-tip-max-width)))
817
+ (setq width (car it)
818
+ lines (cdr it)))
819
+
820
+ (setq tip (popup-create point width height
821
+ :min-height min-height
822
+ :around around
823
+ :margin-left margin-left
824
+ :margin-right margin-right
825
+ :scroll-bar scroll-bar
826
+ :face 'popup-tip-face
827
+ :parent parent
828
+ :parent-offset parent-offset))
829
+
830
+ (unwind-protect
831
+ (when (> (popup-width tip) 0) ; not to be corrupted
832
+ (when (and (not (eq width (popup-width tip))) ; truncated
833
+ (not truncate))
834
+ ;; Refill once again to lines be fitted to popup width
835
+ (setq width (popup-width tip))
836
+ (setq lines (cdr (popup-fill-string string width width))))
837
+
838
+ (popup-set-list tip lines)
839
+ (popup-draw tip)
840
+ (if nowait
841
+ tip
842
+ (clear-this-command-keys)
843
+ (push (read-event prompt) unread-command-events)
844
+ t))
845
+ (unless nowait
846
+ (popup-delete tip))))
847
+
848
+
849
+
850
+ ;; Popup menu
851
+
852
+ (defface popup-menu-face
853
+ '((t (:background "lightgray" :foreground "black")))
854
+ "Face for popup menu."
855
+ :group 'popup)
856
+
857
+ (defface popup-menu-selection-face
858
+ '((t (:background "steelblue" :foreground "white")))
859
+ "Face for popup menu selection."
860
+ :group 'popup)
861
+
862
+ (defvar popup-menu-show-tip-function 'popup-tip
863
+ "Function used for showing tooltip by `popup-menu-show-quick-help'.")
864
+
865
+ (defvar popup-menu-show-quick-help-function 'popup-menu-show-quick-help
866
+ "Function used for showing quick help by `popup-menu*'.")
867
+
868
+ (defun popup-menu-show-help (menu &optional persist item)
869
+ (popup-item-show-help (or item (popup-selected-item menu)) persist))
870
+
871
+ (defun popup-menu-documentation (menu &optional item)
872
+ (popup-item-documentation (or item (popup-selected-item menu))))
873
+
874
+ (defun popup-menu-show-quick-help (menu &optional item &rest args)
875
+ (let* ((point (plist-get args :point))
876
+ (height (or (plist-get args :height) (popup-height menu)))
877
+ (min-height (min height (popup-current-height menu)))
878
+ (around nil)
879
+ (parent-offset (popup-offset menu))
880
+ (doc (popup-menu-documentation menu item)))
881
+ (when (stringp doc)
882
+ (if (popup-hidden-p menu)
883
+ (setq around t
884
+ menu nil
885
+ parent-offset nil)
886
+ (setq point nil))
887
+ (let ((popup-use-optimized-column-computation nil)) ; To avoid wrong positioning
888
+ (apply popup-menu-show-tip-function
889
+ doc
890
+ :point point
891
+ :height height
892
+ :min-height min-height
893
+ :around around
894
+ :parent menu
895
+ :parent-offset parent-offset
896
+ args)))))
897
+
898
+ (defun popup-menu-read-key-sequence (keymap &optional prompt timeout)
899
+ (catch 'timeout
900
+ (let ((timer (and timeout
901
+ (run-with-timer timeout nil
902
+ (lambda ()
903
+ (if (zerop (length (this-command-keys)))
904
+ (throw 'timeout nil))))))
905
+ (old-global-map (current-global-map))
906
+ (temp-global-map (make-sparse-keymap))
907
+ (overriding-terminal-local-map (make-sparse-keymap)))
908
+ (substitute-key-definition 'keyboard-quit 'keyboard-quit
909
+ temp-global-map old-global-map)
910
+ (define-key temp-global-map [menu-bar] (lookup-key old-global-map [menu-bar]))
911
+ (define-key temp-global-map [tool-bar] (lookup-key old-global-map [tool-bar]))
912
+ (set-keymap-parent overriding-terminal-local-map keymap)
913
+ (if (current-local-map)
914
+ (define-key overriding-terminal-local-map [menu-bar]
915
+ (lookup-key (current-local-map) [menu-bar])))
916
+ (unwind-protect
917
+ (progn
918
+ (use-global-map temp-global-map)
919
+ (clear-this-command-keys)
920
+ (with-temp-message prompt
921
+ (read-key-sequence nil)))
922
+ (use-global-map old-global-map)
923
+ (if timer (cancel-timer timer))))))
924
+
925
+ (defun popup-menu-fallback (event default))
926
+
927
+ (defun* popup-menu-event-loop (menu keymap fallback &optional prompt help-delay isearch isearch-cursor-color isearch-keymap isearch-callback &aux key binding)
928
+ (block nil
929
+ (while (popup-live-p menu)
930
+ (and isearch
931
+ (popup-isearch menu
932
+ :cursor-color isearch-cursor-color
933
+ :keymap isearch-keymap
934
+ :callback isearch-callback
935
+ :help-delay help-delay)
936
+ (keyboard-quit))
937
+ (setq key (popup-menu-read-key-sequence keymap prompt help-delay))
938
+ (if (null key)
939
+ (unless (funcall popup-menu-show-quick-help-function menu nil :prompt prompt)
940
+ (clear-this-command-keys)
941
+ (push (read-event prompt) unread-command-events))
942
+ (if (eq (lookup-key (current-global-map) key) 'keyboard-quit)
943
+ (keyboard-quit))
944
+ (setq binding (lookup-key keymap key))
945
+ (cond
946
+ ((eq binding 'popup-close)
947
+ (if (popup-parent menu)
948
+ (return)))
949
+ ((memq binding '(popup-select popup-open))
950
+ (let* ((item (popup-selected-item menu))
951
+ (sublist (popup-item-sublist item)))
952
+ (if sublist
953
+ (popup-aif (popup-cascade-menu sublist
954
+ :around nil
955
+ :parent menu
956
+ :margin-left (popup-margin-left menu)
957
+ :margin-right (popup-margin-right menu)
958
+ :scroll-bar (popup-scroll-bar menu))
959
+ (and it (return it)))
960
+ (if (eq binding 'popup-select)
961
+ (return (popup-item-value-or-self item))))))
962
+ ((eq binding 'popup-next)
963
+ (popup-next menu))
964
+ ((eq binding 'popup-previous)
965
+ (popup-previous menu))
966
+ ((eq binding 'popup-help)
967
+ (popup-menu-show-help menu))
968
+ ((eq binding 'popup-isearch)
969
+ (popup-isearch menu
970
+ :cursor-color isearch-cursor-color
971
+ :keymap isearch-keymap
972
+ :callback isearch-callback
973
+ :help-delay help-delay))
974
+ ((commandp binding)
975
+ (call-interactively binding))
976
+ (t
977
+ (funcall fallback key (key-binding key))))))))
978
+
979
+ ;; popup-menu is used by mouse.el unfairly...
980
+ (defun* popup-menu* (list
981
+ &key
982
+ point
983
+ (around t)
984
+ (width (popup-preferred-width list))
985
+ (height 15)
986
+ margin
987
+ margin-left
988
+ margin-right
989
+ scroll-bar
990
+ symbol
991
+ parent
992
+ parent-offset
993
+ (keymap popup-menu-keymap)
994
+ (fallback 'popup-menu-fallback)
995
+ help-delay
996
+ prompt
997
+ isearch
998
+ (isearch-cursor-color popup-isearch-cursor-color)
999
+ (isearch-keymap popup-isearch-keymap)
1000
+ isearch-callback
1001
+ &aux menu event)
1002
+ (and (eq margin t) (setq margin 1))
1003
+ (or margin-left (setq margin-left margin))
1004
+ (or margin-right (setq margin-right margin))
1005
+ (if (and scroll-bar
1006
+ (integerp margin-right)
1007
+ (> margin-right 0))
1008
+ ;; Make scroll-bar space as margin-right
1009
+ (decf margin-right))
1010
+ (setq menu (popup-create point width height
1011
+ :around around
1012
+ :face 'popup-menu-face
1013
+ :selection-face 'popup-menu-selection-face
1014
+ :margin-left margin-left
1015
+ :margin-right margin-right
1016
+ :scroll-bar scroll-bar
1017
+ :symbol symbol
1018
+ :parent parent))
1019
+ (unwind-protect
1020
+ (progn
1021
+ (popup-set-list menu list)
1022
+ (popup-draw menu)
1023
+ (popup-menu-event-loop menu keymap fallback prompt help-delay isearch
1024
+ isearch-cursor-color isearch-keymap isearch-callback))
1025
+ (popup-delete menu)))
1026
+
1027
+ (defun popup-cascade-menu (list &rest args)
1028
+ "Same to `popup-menu', but an element of `LIST' can be
1029
+ list of submenu."
1030
+ (apply 'popup-menu*
1031
+ (mapcar (lambda (item)
1032
+ (if (consp item)
1033
+ (popup-make-item (car item)
1034
+ :sublist (cdr item)
1035
+ :symbol ">")
1036
+ item))
1037
+ list)
1038
+ :symbol t
1039
+ args))
1040
+
1041
+ (defvar popup-menu-keymap
1042
+ (let ((map (make-sparse-keymap)))
1043
+ (define-key map "\r" 'popup-select)
1044
+ (define-key map "\C-f" 'popup-open)
1045
+ (define-key map [right] 'popup-open)
1046
+ (define-key map "\C-b" 'popup-close)
1047
+ (define-key map [left] 'popup-close)
1048
+
1049
+ (define-key map "\C-n" 'popup-next)
1050
+ (define-key map [down] 'popup-next)
1051
+ (define-key map "\C-p" 'popup-previous)
1052
+ (define-key map [up] 'popup-previous)
1053
+
1054
+ (define-key map [f1] 'popup-help)
1055
+ (define-key map (kbd "\C-?") 'popup-help)
1056
+
1057
+ (define-key map "\C-s" 'popup-isearch)
1058
+ map))
1059
+
1060
+ (provide 'popup)
1061
+ ;;; popup.el ends here