sekka 0.8.2 → 0.8.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
  "入力モード変更"