aboutsummaryrefslogtreecommitdiff
path: root/emms-i18n.el
blob: 492685885e6f9942623f4805f0d988fa1d26a15b (plain) (blame)
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
;;; emms-i18n.el --- functions for handling coding systems  -*- lexical-binding: t; -*-

;; Copyright (C) 2006, 2007, 2008, 2009 Free Software Foundation, Inc.

;; Author: Ye Wenbin <wenbinye@163.com>

;; This file is part of EMMS.

;; This program is free software; you can redistribute it and/or
;; modify it under the terms of the GNU General Public License as
;; published by the Free Software Foundation; either version 3, or (at
;; your option) any later version.

;; This program is distributed in the hope that it will be useful, but
;; WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
;; General Public License for more details.

;; You should have received a copy of the GNU General Public License
;; along with this program; if not, write to the Free Software
;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

;;; Commentary:

;; When reading from process, first check the car part of
;; `emms-i18n-default-coding-system'; if non-nil, use this for
;; decoding, and never detect coding system; if nil, first call
;; `emms-i18n-coding-detect-functions' to get coding system, if
;; success, decode the result, otherwise, use
;; `emms-i18n-detect-coding-function', the Emacs detect coding
;; function, if the coding detected is not in
;; `emms-i18n-never-used-coding-system', decode it, otherwise use
;; locale-coding-system.

;; When writing/sending data to process, first check the cdr part of
;; `emms-i18n-default-coding-system', if non-nil, use this to encode
;; data, otherwise do nothing, that means use
;; `default-process-coding-system' or `process-coding-system-alist' to
;; encode data.

;; Put this file into your load-path and the following into your
;; ~/.emacs:

;;   (require 'emms-i18n)

;;; Code:

(provide 'emms-i18n)

;; TODO: Use defcustom.
(defvar emms-i18n-never-used-coding-system
  '(raw-text undecided)
  "If the `emms-i18n-coding-detect-functions' return a coding
system in this list, use `emms-i18n-default-coding-system'
instead.")

;; TODO: Use defcustom.
(defvar emms-i18n-coding-system-for-read
  'utf-8
  "If coding detect fails, use this for decoding.")

;; TODO: Use defcustom.
(defvar emms-i18n-default-coding-system
  '(no-conversion . no-conversion)
  "If non-nil, use this for decoding and encoding.")

;; TODO: Use defcustom.
(defvar emms-i18n-coding-detect-functions
  nil
  "A list of functions to call to detect codings.")

;; TODO: Use defcustom.
(defvar emms-i18n-detect-max-size
  10000
  "Maximum amount of bytes to detect the coding system.  nil
means to scan the whole buffer.")

(defun emms-i18n-iconv (from to str)
  "Convert string STR from FROM coding to TO coding."
  (if (and from to)
      (decode-coding-string
       (encode-coding-string str to)
       from)
    str))

(defun emms-i18n-iconv-region (beg end from to)
  (when (and from to)
    (save-restriction
      (narrow-to-region beg end)
      (encode-coding-region (point-min) (point-max) to)
      (decode-coding-region (point-min) (point-max) from))))

(defun emms-i18n-iconv-buffer (from to &optional buf)
  "Convert buffer BUF from FROM coding to TO coding.  BUF
defaults to the current buffer."
  (save-excursion
    (and buf (set-buffer buf))
    (emms-i18n-iconv-region (point-min) (point-max) from to)))

(defun emms-i18n-set-default-coding-system (read-coding write-coding)
  "Set `emms-i18n-default-coding-system'."
  (interactive "zSet coding system for read: \nzSet coding system for write: ")
  (setq emms-i18n-default-coding-system
        (cons
         (and (coding-system-p read-coding) read-coding)
         (and (coding-system-p write-coding) write-coding)))
  (message (concat
            (if (car emms-i18n-default-coding-system)
                (format "The coding system for reading is %S." (car emms-i18n-default-coding-system))
              "Good, you want me to detect the coding system!")
            (format " The coding system for writing is %S."
                    (or (cdr emms-i18n-default-coding-system)
                        (cdr default-process-coding-system))))))

(defun emms-i18n-call-process-simple (&rest args)
  "Run a program and return the program result.
If the car part of `emms-i18n-default-coding-system' is non-nil,
the program result will be decoded using the car part of
`emms-i18n-default-coding-system'.  Otherwise, use
`emms-i18n-coding-detect-functions' to detect the coding system
of the result.  If the `emms-i18n-coding-detect-functions'
failed, use `emms-i18n-detect-coding-function' to detect coding
system.  If all the coding systems are nil or in
`emms-i18n-never-used-coding-system', decode the result using
`emms-i18n-coding-system-for-read'.

ARGS are the same as in `call-process', except BUFFER should
always have the value t.  Otherwise the coding detection will not
be performed."
  (let ((default-process-coding-system (copy-tree default-process-coding-system))
        (process-coding-system-alist nil) exit pos)
    (when (eq (nth 2 args) 't)
      (setcar default-process-coding-system (car emms-i18n-default-coding-system))
      (setq pos (point)))
    (setq exit (apply 'call-process args))
    (when (and (eq (nth 2 args) 't)
               (eq (car emms-i18n-default-coding-system) 'no-conversion))
      (save-restriction
        (narrow-to-region pos (point))
        (decode-coding-region (point-min) (point-max) (emms-i18n-detect-buffer-coding-system))))
    exit))

;; TODO: Is this function useful?
(defun emms-i18n-call-process (&rest args)
  "Run the program like `call-process'.  If the cdr part of
`emms-i18n-default-coding-system' is non-nil, the string in ARGS
will be encoded by the cdr part of
`emms-i18n-default-coding-system'; otherwise, all parameters are
simply passed to `call-process'."
  (with-temp-buffer
    (if (cdr emms-i18n-default-coding-system)
        (let ((default-process-coding-system emms-i18n-default-coding-system)
              (process-coding-system-alist nil))
          (apply 'call-process args))
      (apply 'call-process args))))

(defun emms-i18n-detect-coding-function (size)
  (detect-coding-region (point)
                        (+ (if (null emms-i18n-detect-max-size)
                               size
                             (min size emms-i18n-detect-max-size))
                           (point)) t))

(defun emms-i18n-detect-buffer-coding-system (&optional buf)
  "Before calling this function, make sure the buffer is literal."
  (let ((size (- (point-max) (point-min)))
        (_func (append emms-i18n-coding-detect-functions 'emms-i18n-detect-coding-function))
        coding)
    (save-excursion
      (and buf (set-buffer buf))
      (goto-char (point-min))
      (when (> size 0)
        (setq coding (run-hook-with-args-until-success 'func size))
        (if (member (coding-system-base coding) emms-i18n-never-used-coding-system)
            (setq coding (emms-i18n-detect-coding-function size))))
      (if (or (null coding) (member (coding-system-base coding) emms-i18n-never-used-coding-system))
          emms-i18n-coding-system-for-read
        coding))))

;;; emms-i18n.el ends here