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.
@@ -2,7 +2,7 @@
2
2
  ;;
3
3
  ;; "sekka.el" is a client for Sekka server
4
4
  ;;
5
- ;; Copyright (C) 2010 Kiyoka Nishiyama
5
+ ;; Copyright (C) 2010,2011 Kiyoka Nishiyama
6
6
  ;; This program was derived from sumibi.el and yc.el-4.0.13(auther: knak)
7
7
  ;;
8
8
  ;;
@@ -25,6 +25,7 @@
25
25
  ;;; Code:
26
26
  (require 'cl)
27
27
  (require 'http-get)
28
+ (require 'popup)
28
29
 
29
30
  ;;;
30
31
  ;;;
@@ -55,6 +56,11 @@
55
56
  :type 'string
56
57
  :group 'sekka)
57
58
 
59
+ (defcustom sekka-no-proxy-hosts ""
60
+ "http proxyを使わないホスト名を指定する。複数指定する場合は、コンマで区切る。"
61
+ :type 'string
62
+ :group 'sekka)
63
+
58
64
  (defcustom sekka-realtime-guide-running-seconds 30
59
65
  "リアルタイムガイド表示の継続時間(秒数)・ゼロでガイド表示機能が無効になる"
60
66
  :type 'integer
@@ -67,7 +73,7 @@
67
73
 
68
74
  (defcustom sekka-realtime-guide-interval 0.2
69
75
  "リアルタイムガイド表示を更新する時間間隔"
70
- :type 'integer
76
+ :type 'float
71
77
  :group 'sekka)
72
78
 
73
79
  (defcustom sekka-roman-method "normal"
@@ -87,6 +93,17 @@
87
93
  (const :tag "english(us)-keyboard" "en"))
88
94
  :group 'sekka)
89
95
 
96
+ (defcustom sekka-jisyo-filename "~/.sekka-jisyo"
97
+ "sekka-jisyoのファイル名を指定する"
98
+ :type 'string
99
+ :group 'sekka)
100
+
101
+ (defcustom sekka-use-googleime t
102
+ "変換結果に、漢字のエントリ type=j が含まれていなかったら、自動的にGoogleIMEを APIを使って変換候補を取得する。
103
+ non-nil で明示的に呼びだすまでGoogleIMEは起動しない。"
104
+ :type 'boolean
105
+ :group 'sekka)
106
+
90
107
 
91
108
  (defface sekka-guide-face
92
109
  '((((class color) (background light)) (:background "#E0E0E0" :foreground "#F03030")))
@@ -125,6 +142,8 @@
125
142
 
126
143
  (defconst sekka-login-name (user-login-name))
127
144
 
145
+ (defconst sekka-tango-index 0)
146
+ (defconst sekka-annotation-index 1)
128
147
  (defconst sekka-kind-index 3)
129
148
  (defconst sekka-id-index 4)
130
149
 
@@ -164,6 +183,8 @@
164
183
  (defvar sekka-cand-cur-backup 0) ; カレント候補番号(UNDO用に退避する変数)
165
184
  (defvar sekka-cand-len nil) ; 候補数
166
185
  (defvar sekka-last-fix "") ; 最後に確定した文字列
186
+ (defvar sekka-last-roman "") ; 最後にsekka-serverにリクエストしたローマ字文字列
187
+ (defvar sekka-select-operation-times 0) ; 選択操作回数
167
188
  (defvar sekka-henkan-kouho-list nil) ; 変換結果リスト(サーバから帰ってきたデータそのもの)
168
189
 
169
190
 
@@ -271,13 +292,26 @@
271
292
  ;; )
272
293
  (defun sekka-rest-request (func-name arg-alist)
273
294
  (if sekka-psudo-server
274
- ;; クライアント単体で仮想的にサーバーに接続しているようにしてテストするモード
275
- "((\"変換\" nil \"へんかん\" j 0) (\"変化\" nil \"へんか\" j 1) (\"ヘンカン\" nil \"へんかん\" k 2) (\"へんかん\" nil \"へんかん\" h 3))"
276
- ;;"((\"変換\" nil \"へんかん\" j 0) (\"変化\" nil \"へんか\" j 1))"
295
+ (cond
296
+ ((string-equal func-name "henkan")
297
+ ;; クライアント単体で仮想的にサーバーに接続しているようにしてテストするモード
298
+ ;; result of /henkan
299
+ ;;"((\"変換\" nil \"へんかん\" j 0) (\"変化\" nil \"へんか\" j 1) (\"ヘンカン\" nil \"へんかん\" k 2) (\"へんかん\" nil \"へんかん\" h 3))")
300
+ "((\"ヨンモジジュクゴ\" nil \"よんもじじゅくご\" k 0) (\"よんもじじゅくご\" nil \"よんもじじゅくご\" h 1))")
301
+ ((string-equal func-name "googleime")
302
+ ;; result of /google_ime
303
+ ;; 1) よんもじじゅくご
304
+ "(\"四文字熟語\" \"4文字熟語\" \"4文字熟語\" \"よんもじじゅくご\" \"ヨンモジジュクゴ\")"
305
+ ;; 2) しょかいきどう
306
+ ;; "(\"初回起動\", \"諸快気堂\", \"諸開基堂\", \"しょかいきどう\", \"ショカイキドウ\")"
307
+ ))
277
308
  ;; 実際のサーバに接続する
278
309
  (let ((command
279
310
  (concat
280
311
  sekka-curl " --silent --show-error "
312
+ (if (< 0 (length sekka-no-proxy-hosts))
313
+ (concat " --noproxy " sekka-no-proxy-hosts)
314
+ "")
281
315
  (format " --max-time %d " sekka-server-timeout)
282
316
  " --insecure "
283
317
  " --header 'Content-Type: application/x-www-form-urlencoded' "
@@ -351,6 +385,28 @@
351
385
  (message result)
352
386
  t))
353
387
 
388
+
389
+ ;;
390
+ ;; GoogleImeAPIリクエストをサーバーに送る
391
+ ;;
392
+ (defun sekka-googleime-request (yomi)
393
+ (sekka-debug-print (format "googleime yomi=[%s]\n" yomi))
394
+
395
+ ;;(message "Requesting to sekka server...")
396
+
397
+ (let ((result (sekka-rest-request "googleime" `(
398
+ (yomi . ,yomi)))))
399
+ (sekka-debug-print (format "googleime-result:%S\n" result))
400
+ (progn
401
+ (message nil)
402
+ (condition-case err
403
+ (read result)
404
+ (end-of-file
405
+ (progn
406
+ (message "Parse error for parsing result of Sekka Server.")
407
+ '()))))))
408
+
409
+
354
410
  ;;
355
411
  ;; ユーザー語彙をサーバーに再度登録する。
356
412
  ;;
@@ -362,9 +418,9 @@
362
418
 
363
419
  ;;
364
420
  ;; ユーザー語彙をサーバーに登録する。
365
- ;;
366
- (defun sekka-register-userdict-internal ()
367
- (let* ((str (sekka-get-jisyo-str "~/.sekka-jisyo"))
421
+ ;; only-first が t の時は、1ブロック目だけを登録する
422
+ (defun sekka-register-userdict-internal (&optional only-first)
423
+ (let* ((str (sekka-get-jisyo-str sekka-jisyo-filename))
368
424
  (str-lst (sekka-divide-into-few-line str)))
369
425
  (mapcar
370
426
  (lambda (x)
@@ -373,7 +429,9 @@
373
429
  (let ((result (sekka-rest-request "register" `((dict . ,x)))))
374
430
  (sekka-debug-print (format "register-result:%S\n" result))
375
431
  (message result)))
376
- str-lst)
432
+ (if only-first
433
+ (list (car str-lst))
434
+ str-lst))
377
435
  t))
378
436
 
379
437
 
@@ -427,25 +485,54 @@
427
485
  (reverse result))
428
486
  '()))
429
487
 
488
+
489
+ (defun sekka-file-existp (file)
490
+ "FILE が存在するかどうかをチェックする。 t か nil で結果を返す"
491
+ (let* ((file (or (car-safe file)
492
+ file))
493
+ (file (expand-file-name file)))
494
+ (file-exists-p file)))
495
+
496
+
430
497
  (defun sekka-get-jisyo-str (file &optional nomsg)
431
498
  "FILE を開いて Sekka辞書バッファを作り、バッファ1行1文字列のリストで返す"
432
- (when file
433
- (let* ((file (or (car-safe file)
434
- file))
435
- (file (expand-file-name file)))
436
- (if (not (file-exists-p file))
437
- (progn
438
- (message (format "Sekka辞書 %s が存在しません..." file))
439
- nil)
440
- (let ((str "")
441
- (buf-name (file-name-nondirectory file)))
442
- (save-excursion
443
- (find-file-read-only file)
444
- (setq str (with-current-buffer (get-buffer buf-name)
445
- (buffer-substring-no-properties (point-min) (point-max))))
446
- (message (format "Sekka辞書 %s を開いています...完了!" (file-name-nondirectory file)))
447
- (kill-buffer-if-not-modified (get-buffer buf-name)))
448
- str)))))
499
+ (if (sekka-file-existp file)
500
+ (let ((str "")
501
+ (buf-name (file-name-nondirectory file)))
502
+ (save-excursion
503
+ (find-file-read-only file)
504
+ (setq str (with-current-buffer (get-buffer buf-name)
505
+ (buffer-substring-no-properties (point-min) (point-max))))
506
+ (message (format "Sekka辞書 %s を開いています...完了!" (file-name-nondirectory file)))
507
+ (kill-buffer-if-not-modified (get-buffer buf-name)))
508
+ str)
509
+ (message (format "Sekka辞書 %s が存在しません..." file))))
510
+
511
+
512
+ (defun sekka-add-new-word-to-jisyo (file yomi tango)
513
+ "FILE Sekka辞書ファイルと見做し、ファイルの先頭に「読み」と「単語」のペアを書き込む
514
+ 登録が成功したかどうかを t or nil で返す"
515
+ (if (sekka-file-existp file)
516
+ (let ((buf-name (file-name-nondirectory file))
517
+ (added nil))
518
+ (save-excursion
519
+ (find-file file)
520
+ (with-current-buffer (get-buffer buf-name)
521
+ (goto-char (point-min))
522
+ (let ((newstr (format "%s /%s/" yomi tango)))
523
+ (when (not (search-forward newstr nil t))
524
+ (insert newstr)
525
+ (insert "\n")
526
+ (save-buffer)
527
+ (setq added t)
528
+ )))
529
+ (kill-buffer-if-not-modified (get-buffer buf-name)))
530
+ added)
531
+ (progn
532
+ (message (format "Sekka辞書 %s が存在しません..." file))
533
+ nil)))
534
+
535
+
449
536
 
450
537
 
451
538
  ;; ポータブル文字列置換( EmacsとXEmacsの両方で動く )
@@ -612,8 +699,57 @@
612
699
  (define-key sekka-select-mode-map "\C-k" 'sekka-select-katakana)
613
700
  (define-key sekka-select-mode-map "\C-l" 'sekka-select-hankaku)
614
701
  (define-key sekka-select-mode-map "\C-e" 'sekka-select-zenkaku)
702
+ (define-key sekka-select-mode-map "\C-r" 'sekka-add-new-word)
703
+
704
+
705
+ (defvar sekka-popup-menu-keymap
706
+ (let ((map (make-sparse-keymap)))
707
+ (define-key map "\r" 'popup-select)
708
+ (define-key map "\C-f" 'popup-open)
709
+ (define-key map [right] 'popup-open)
710
+ (define-key map "\C-b" 'popup-close)
711
+ (define-key map [left] 'popup-close)
712
+
713
+ (define-key map "\C-n" 'popup-next)
714
+ (define-key map "\C-j" 'popup-next)
715
+ (define-key map [down] 'popup-next)
716
+ (define-key map "\C-p" 'popup-previous)
717
+ (define-key map [up] 'popup-previous)
718
+
719
+ (define-key map [f1] 'popup-help)
720
+ (define-key map (kbd "\C-?") 'popup-help)
721
+
722
+ (define-key map "\C-s" 'popup-isearch)
723
+ (define-key map "\C-g" 'popup-close)
724
+ map))
725
+
726
+ ;; 選択操作回数のインクリメント
727
+ (defun sekka-select-operation-inc ()
728
+ (incf sekka-select-operation-times)
729
+ (when (< 3 sekka-select-operation-times)
730
+ (sekka-select-operation-reset)
731
+ (let* ((lst
732
+ (mapcar
733
+ (lambda (x)
734
+ (concat
735
+ (nth sekka-tango-index x)
736
+ " ; "
737
+ (nth sekka-annotation-index x)))
738
+ sekka-henkan-kouho-list))
739
+ (map (make-sparse-keymap))
740
+ (result
741
+ (popup-menu* lst
742
+ :scroll-bar t
743
+ :margin t
744
+ :keymap sekka-popup-menu-keymap)))
745
+ (let ((selected-word (car (split-string result " "))))
746
+ (setq sekka-cand-cur (sekka-find-by-tango selected-word))
747
+ (sekka-select-kakutei)))))
748
+
615
749
 
616
-
750
+ ;; 選択操作回数のリセット
751
+ (defun sekka-select-operation-reset ()
752
+ (setq sekka-select-operation-times 0))
617
753
 
618
754
  ;; 変換を確定し入力されたキーを再入力する関数
619
755
  (defun sekka-kakutei-and-self-insert (arg)
@@ -647,6 +783,7 @@
647
783
  (sekka-kakutei-request key tango)))
648
784
  (setq sekka-select-mode nil)
649
785
  (run-hooks 'sekka-select-mode-end-hook)
786
+ (sekka-select-operation-reset)
650
787
  (sekka-select-update-display)
651
788
  (sekka-history-push))
652
789
 
@@ -671,6 +808,7 @@
671
808
  (decf sekka-cand-cur)
672
809
  (when (> 0 sekka-cand-cur)
673
810
  (setq sekka-cand-cur (- sekka-cand-len 1)))
811
+ (sekka-select-operation-inc)
674
812
  (sekka-select-update-display))
675
813
 
676
814
  ;; 次の候補に進める
@@ -682,8 +820,21 @@
682
820
  (if (< sekka-cand-cur (- sekka-cand-len 1))
683
821
  (+ sekka-cand-cur 1)
684
822
  0))
823
+ (sekka-select-operation-inc)
685
824
  (sekka-select-update-display))
686
825
 
826
+ ;; 指定された tango のindex番号を返す
827
+ (defun sekka-find-by-tango ( tango )
828
+ (let ((result-index nil))
829
+ (mapcar
830
+ (lambda (x)
831
+ (let ((_tango (nth sekka-tango-index x)))
832
+ (when (string-equal _tango tango)
833
+ (setq result-index (nth sekka-id-index x)))))
834
+ sekka-henkan-kouho-list)
835
+ (sekka-debug-print (format "sekka-find-by-tango: tango=%s result=%S \n" tango result-index))
836
+ result-index))
837
+
687
838
  ;; 指定された type の候補を抜き出す
688
839
  (defun sekka-select-by-type-filter ( _type )
689
840
  (let ((lst '()))
@@ -693,27 +844,35 @@
693
844
  (when (eq sym _type)
694
845
  (push x lst))))
695
846
  sekka-henkan-kouho-list)
696
- (sekka-debug-print (format "filterd-lst = %S" (reverse lst)))
847
+ (sekka-debug-print (format "filterd-lst = %S\n" (reverse lst)))
697
848
  (car (reverse lst))))
698
849
 
850
+ ;; 指定された type の候補が存在するか調べる
851
+ (defun sekka-include-typep ( _type )
852
+ (not (null (sekka-select-by-type-filter _type))))
853
+
699
854
  ;; 指定された type の候補に強制的に切りかえる
855
+ ;; 切りかえが成功したかどうかを t or nil で返す。
700
856
  (defun sekka-select-by-type ( _type )
701
857
  (let ((kouho (sekka-select-by-type-filter _type)))
702
858
  (if (null kouho)
703
- (cond
704
- ((eq _type 'j)
705
- (message "Sekka: 漢字の候補はありません。"))
706
- ((eq _type 'h)
707
- (message "Sekka: ひらがなの候補はありません。"))
708
- ((eq _type 'k)
709
- (message "Sekka: カタカナの候補はありません。"))
710
- ((eq _type 'l)
711
- (message "Sekka: 半角の候補はありません。"))
712
- ((eq _type 'z)
713
- (message "Sekka: 全角の候補はありません。")))
859
+ (begin
860
+ (cond
861
+ ((eq _type 'j)
862
+ (message "Sekka: 漢字の候補はありません。"))
863
+ ((eq _type 'h)
864
+ (message "Sekka: ひらがなの候補はありません。"))
865
+ ((eq _type 'k)
866
+ (message "Sekka: カタカナの候補はありません。"))
867
+ ((eq _type 'l)
868
+ (message "Sekka: 半角の候補はありません。"))
869
+ ((eq _type 'z)
870
+ (message "Sekka: 全角の候補はありません。"))
871
+ nil))
714
872
  (let ((num (nth sekka-id-index kouho)))
715
873
  (setq sekka-cand-cur num)
716
- (sekka-select-update-display)))))
874
+ (sekka-select-update-display)
875
+ t))))
717
876
 
718
877
  (defun sekka-select-kanji ()
719
878
  "漢字候補に強制的に切りかえる"
@@ -741,6 +900,65 @@
741
900
  (sekka-select-by-type 'z))
742
901
 
743
902
 
903
+ (defun sekka-replace-kakutei-word (b e insert-word)
904
+ ;; UNDO抑制開始
905
+ (sekka-disable-undo)
906
+
907
+ (delete-region b e)
908
+
909
+ (insert insert-word)
910
+ (message (format "replaced by new word [%s]" insert-word))
911
+ ;; UNDO再開
912
+ (sekka-enable-undo))
913
+
914
+
915
+ ;; 登録語リストからユーザーに該当単語を選択してもらう
916
+ (defun sekka-add-new-word-sub (yomi lst)
917
+ (let* ((etc "(自分で入力する)")
918
+ (lst (if (stringp lst)
919
+ (progn
920
+ (message lst) ;; サーバーから返ってきたエラーメッセージを表示
921
+ '())
922
+ lst))
923
+ (result (popup-menu*
924
+ (append lst `(,etc))
925
+ :margin t
926
+ :keymap sekka-popup-menu-keymap))
927
+ (b (copy-marker sekka-fence-start))
928
+ (e (copy-marker sekka-fence-end)))
929
+ (let ((tango
930
+ (if (string-equal result etc)
931
+ (save-current-buffer
932
+ (read-string (format "%sに対応する単語:" yomi)))
933
+ result)))
934
+ ;; 新しい単語で確定する
935
+ (sekka-replace-kakutei-word (marker-position b)
936
+ (marker-position e)
937
+ tango)
938
+ ;; .sekka-jisyoとサーバーの両方に新しい単語を登録する
939
+ (let ((added (sekka-add-new-word-to-jisyo sekka-jisyo-filename yomi tango)))
940
+ (if added
941
+ (progn
942
+ (sekka-register-userdict-internal t)
943
+ (message (format "Sekka辞書 %s に単語(%s /%s/)を保存しました!" sekka-jisyo-filename yomi tango)))
944
+ (message (format "Sekka辞書 %s に 単語(%s /%s/)を追加しませんでした(登録済)" sekka-jisyo-filename yomi tango)))))))
945
+
946
+
947
+ (defun sekka-add-new-word ()
948
+ "変換候補のよみ(平仮名)に対応する新しい単語を追加する"
949
+ (interactive)
950
+ (setq case-fold-search nil)
951
+ (when (sekka-select-by-type 'h)
952
+ (let* ((kouho (nth sekka-cand-cur sekka-henkan-kouho-list))
953
+ (hiragana (car kouho)))
954
+ (sekka-debug-print (format "sekka-register-new-word: sekka-last-roman=[%s] hiragana=%s result=%S\n" sekka-last-roman hiragana (string-match-p "^[A-Z][^A-Z]+$" sekka-last-roman)))
955
+ (when (string-match-p "^[A-Z][^A-Z]+$" sekka-last-roman)
956
+ (sekka-select-kakutei)
957
+ (sekka-add-new-word-sub
958
+ hiragana
959
+ (sekka-googleime-request hiragana))))))
960
+
961
+
744
962
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
745
963
  ;; 変換履歴操作関数
746
964
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -895,14 +1113,17 @@
895
1113
  (when (sekka-henkan-region b e)
896
1114
  (if (eq (char-before b) ?/)
897
1115
  (setq b (- b 1)))
1116
+ (setq sekka-last-roman (buffer-substring-no-properties b e))
898
1117
  (delete-region b e)
899
1118
  (goto-char b)
900
1119
  (insert (sekka-get-display-string))
901
1120
  (setq e (point))
902
1121
  (sekka-display-function b e nil)
903
1122
  (sekka-select-kakutei)
1123
+ (when sekka-use-googleime
1124
+ (when (not (sekka-include-typep 'j))
1125
+ (sekka-add-new-word)))
904
1126
  )))))
905
-
906
1127
 
907
1128
  ((sekka-kanji (preceding-char))
908
1129
 
@@ -1198,7 +1419,7 @@ point から行頭方向に同種の文字列が続く間を漢字変換しま
1198
1419
  (setq default-input-method "japanese-sekka")
1199
1420
 
1200
1421
  (defconst sekka-version
1201
- "0.8.2" ;;SEKKA-VERSION
1422
+ "0.8.3" ;;SEKKA-VERSION
1202
1423
  )
1203
1424
  (defun sekka-version (&optional arg)
1204
1425
  "入力モード変更"