diff options
author | 2009-02-28 20:55:22 -0500 | |
---|---|---|
committer | 2009-02-28 20:55:22 -0500 | |
commit | b1d103ecb28589d507477715f25fba5641d247c8 (patch) | |
tree | 2aff52d12db043853c2688added7c31e758460a1 | |
parent | 36aaa46d7f71e3efa26a7fdf66fac537c060f414 (diff) | |
download | textadept-b1d103ecb28589d507477715f25fba5641d247c8.tar.gz textadept-b1d103ecb28589d507477715f25fba5641d247c8.zip |
Use UTF-8 internally and respect platform filename encoding.
Added 'textadept.iconv' function to interface with GLib's g_convert() and set
global _CHARSET to be the platform's filename encoding/code page.
-rw-r--r-- | core/.buffer.lua | 1 | ||||
-rw-r--r-- | core/events.lua | 16 | ||||
-rw-r--r-- | core/ext/find.lua | 9 | ||||
-rw-r--r-- | core/ext/pm/file_browser.lua | 48 | ||||
-rw-r--r-- | core/ext/pm/modules_browser.lua | 32 | ||||
-rw-r--r-- | core/file_io.lua | 65 | ||||
-rw-r--r-- | modules/cpp/commands.lua | 4 | ||||
-rw-r--r-- | modules/cpp/snippets.lua | 2 | ||||
-rw-r--r-- | modules/lua/commands.lua | 6 | ||||
-rw-r--r-- | modules/textadept/run.lua | 13 | ||||
-rw-r--r-- | src/lua_interface.c | 18 |
11 files changed, 132 insertions, 82 deletions
diff --git a/core/.buffer.lua b/core/.buffer.lua index 085c5eaa..62672fa5 100644 --- a/core/.buffer.lua +++ b/core/.buffer.lua @@ -18,6 +18,7 @@ module('buffer') -- @field dirty Flag indicating whether or not the buffer has been modified -- since it was last saved. -- @field filename The absolute path to the file associated with this buffer. +-- It is encoded in UTF-8. Use 'textadept.iconv()' for charset conversions. -- @field anchor The position of the opposite end of the selection to the -- caret. -- @field auto_c_auto_hide Flag indicating whether or not autocompletion is diff --git a/core/events.lua b/core/events.lua index b28b36ee..6767ebac 100644 --- a/core/events.lua +++ b/core/events.lua @@ -371,15 +371,17 @@ add_handler('save_point_left', end) add_handler('uri_dropped', - function(uris) + function(utf8_uris) local lfs = require 'lfs' - for uri in uris:gmatch('[^\r\n\f]+') do - if uri:find('^file://') then - uri = uri:match('^file://([^\r\n\f]+)') - uri = uri:gsub('%%20', ' ') -- sub back for spaces - if WIN32 then uri = uri:sub(2, -1) end -- ignore leading '/' + for utf8_uri in utf8_uris:gmatch('[^\r\n\f]+') do + if utf8_uri:find('^file://') then + utf8_uri = utf8_uri:match('^file://([^\r\n\f]+)') + utf8_uri = utf8_uri:gsub('%%(%x%x)', + function(hex) return string.char(tonumber(hex, 16)) end) + if WIN32 then utf8_uri = utf8_uri:sub(2, -1) end -- ignore leading '/' + local uri = textadept.iconv(utf8_uri, _CHARSET, 'UTF-8') if lfs.attributes(uri).mode ~= 'directory' then - textadept.io.open(uri) + textadept.io.open(utf8_uri) end end end diff --git a/core/ext/find.lua b/core/ext/find.lua index 6bbeba0b..064a7ddb 100644 --- a/core/ext/find.lua +++ b/core/ext/find.lua @@ -81,7 +81,7 @@ function find.find(text, next, flags, nowrap, wrapped) end else -- find in files - local dir = + local utf8_dir = cocoa_dialog('fileselect', { title = locale.FIND_IN_FILES_TITLE, text = locale.FIND_IN_FILES_TEXT, @@ -89,12 +89,13 @@ function find.find(text, next, flags, nowrap, wrapped) ['with-directory'] = (buffer.filename or ''):match('^.+[/\\]'), ['no-newline'] = true }) - if #dir > 0 then + if #utf8_dir > 0 then if not find.lua then text = text:gsub('([().*+?^$%%[%]-])', '%%%1') end if not find.match_case then text = text:lower() end if find.whole_word then text = '[^%W_]'..text..'[^%W_]' end local match_case = find.match_case local whole_word = find.whole_word + local iconv = textadept.iconv local format = string.format local matches = { 'Find: '..text } function search_file(file) @@ -104,6 +105,7 @@ function find.find(text, next, flags, nowrap, wrapped) if not match_case then optimized_line = line:lower() end if whole_word then optimized_line = ' '..line..' ' end if string.find(optimized_line, text) then + file = iconv(file, 'UTF-8', _CHARSET) matches[#matches + 1] = format('%s:%s:%s', file, line_num, line) end line_num = line_num + 1 @@ -122,6 +124,7 @@ function find.find(text, next, flags, nowrap, wrapped) end end end + local dir = iconv(utf8_dir, _CHARSET, 'UTF-8') search_dir(dir) if #matches == 1 then matches[2] = locale.FIND_NO_RESULTS end matches[#matches + 1] = '' @@ -293,7 +296,7 @@ end textadept.events.add_handler('double_click', goto_file) --- --- [Local function] Goes to the next or previous file found relative to the file +-- Goes to the next or previous file found relative to the file -- on the current line. -- @param next Flag indicating whether or not to go to the next file. function find.goto_file_in_list(next) diff --git a/core/ext/pm/file_browser.lua b/core/ext/pm/file_browser.lua index 21309a21..8bff30f0 100644 --- a/core/ext/pm/file_browser.lua +++ b/core/ext/pm/file_browser.lua @@ -25,17 +25,19 @@ function matches(entry_text) end function get_contents_for(full_path) + local iconv = textadept.iconv local dir = {} - local dirpath = table.concat(full_path, '/') + local dirpath = iconv(table.concat(full_path, '/'), _CHARSET, 'UTF-8') local path = lfs.attributes(dirpath) - local invalid_file = show_dot_files and '^%.%.?$' or '^%.' if path and path.mode == 'directory' then - for name in lfs.dir(dirpath) do - if not name:find(invalid_file) then - dir[name] = { text = name } - if lfs.attributes(dirpath..'/'..name, 'mode') == 'directory' then - dir[name].parent = true - dir[name].pixbuf = 'gtk-directory' + local invalid_file = show_dot_files and '^%.%.?$' or '^%.' + for filename in lfs.dir(dirpath) do + if not filename:find(invalid_file) then + local utf8_filename = iconv(filename, 'UTF-8', _CHARSET) + dir[utf8_filename] = { text = utf8_filename } + if lfs.attributes(dirpath..'/'..filename, 'mode') == 'directory' then + dir[utf8_filename].parent = true + dir[utf8_filename].pixbuf = 'gtk-directory' end end end @@ -44,8 +46,8 @@ function get_contents_for(full_path) end function perform_action(selected_item) - local filepath = table.concat(selected_item, '/') - textadept.io.open(filepath) + local utf8_filepath = table.concat(selected_item, '/') + textadept.io.open(utf8_filepath) view:focus() end @@ -61,9 +63,10 @@ function get_context_menu(selected_item) end function perform_menu_action(menu_id, selected_item) - local filepath = table.concat(selected_item, '/'):gsub('[/\\]+', '/') + local utf8_filepath = table.concat(selected_item, '/'):gsub('[/\\]+', '/') + local filepath = textadept.iconv(utf8_filepath, _CHARSET, 'UTF-8') if menu_id == ID.CHANGE_DIR then - textadept.pm.entry_text = filepath + textadept.pm.entry_text = utf8_filepath textadept.pm.activate() elseif menu_id == ID.FILE_INFO then local date_format = '%D %T' @@ -76,7 +79,7 @@ function perform_menu_action(menu_id, selected_item) os.date(date_format, attr.change)) cocoa_dialog('textbox', { ['informative-text'] = - string.format(locale.PM_BROWSER_FILE_INFO_TEXT, filepath), + string.format(locale.PM_BROWSER_FILE_INFO_TEXT, utf8_filepath), text = out, button1 = locale.PM_BROWSER_FILE_INFO_OK, editable = false @@ -90,15 +93,18 @@ end -- load the dropped directory (if any) into the file browser; events.lua's -- "uri_dropped" handler already opens dropped files textadept.events.add_handler('uri_dropped', - function(uris) - for uri in uris:gmatch('[^\r\n\f]+') do - if uri:find('^file://') then - uri = uri:match('^file://([^\r\n\f]+)') - uri = uri:gsub('%%20', ' ') -- sub back for spaces - if WIN32 then uri = uri:sub(2, -1) end -- ignore leading '/' + function(utf8_uris) + local lfs = require 'lfs' + for utf8_uri in utf8_uris:gmatch('[^\r\n\f]+') do + if utf8_uri:find('^file://') then + utf8_uri = utf8_uri:match('^file://([^\r\n\f]+)') + utf8_uri = utf8_uri:gsub('%%(%x%x)', + function(hex) return string.char(tonumber(hex, 16)) end) + if WIN32 then utf8_uri = utf8_uri:sub(2, -1) end -- ignore leading '/' + local uri = textadept.iconv(utf8_uri, _CHARSET, 'UTF-8') if lfs.attributes(uri).mode == 'directory' then - textadept.pm.add_browser(uri) - textadept.pm.entry_text = uri + textadept.pm.add_browser(utf8_uri) + textadept.pm.entry_text = utf8_uri textadept.pm.activate() end end diff --git a/core/ext/pm/modules_browser.lua b/core/ext/pm/modules_browser.lua index 37e83592..4cbe715c 100644 --- a/core/ext/pm/modules_browser.lua +++ b/core/ext/pm/modules_browser.lua @@ -71,7 +71,9 @@ local keys = _G.keys if type(keys) == 'table' then keys.$1 = { al = { - m = { textadept.io.open, _HOME..'/modules/$1/init.lua' }, + m = { textadept.io.open, + textadept.iconv(_HOME..'/modules/$1/init.lua', + 'UTF-8', _CHARSET) }, }, } end @@ -82,20 +84,22 @@ function matches(entry_text) end local function modify_path(path) - path[1] = _HOME..'/modules' + path[1] = textadept.iconv(_HOME..'/modules', 'UTF-8', _CHARSET) return path end function get_contents_for(full_path) full_path = modify_path(full_path) + local iconv = textadept.iconv local dir = {} - local dirpath = table.concat(full_path, '/') - for name in lfs.dir(dirpath) do - if not name:find('^%.') then - dir[name] = { text = name } - if lfs.attributes(dirpath..'/'..name, 'mode') == 'directory' then - dir[name].parent = true - dir[name].pixbuf = 'gtk-directory' + local dirpath = iconv(table.concat(full_path, '/'), _CHARSET, 'UTF-8') + for filename in lfs.dir(dirpath) do + if not filename:find('^%.') then + local utf8_filename = iconv(filename, 'UTF-8', _CHARSET) + dir[utf8_filename] = { text = utf8_filename } + if lfs.attributes(dirpath..'/'..filename, 'mode') == 'directory' then + dir[utf8_filename].parent = true + dir[utf8_filename].pixbuf = 'gtk-directory' end end end @@ -104,8 +108,8 @@ end function perform_action(selected_item) selected_item = modify_path(selected_item) - local filepath = table.concat(selected_item, '/') - textadept.io.open(filepath) + local utf8_filepath = table.concat(selected_item, '/') + textadept.io.open(utf8_filepath) view:focus() end @@ -183,10 +187,12 @@ function perform_menu_action(menu_id, selected_item) return end elseif menu_id == ID.CONF_MIME_TYPES then - textadept.io.open(_HOME..'/core/ext/mime_types.lua') + textadept.io.open( + textadept.iconv(_HOME..'/core/ext/mime_types.lua', 'UTF-8', _CHARSET)) elseif menu_id == ID.CONF_KEY_COMMANDS then if textadept.key_commands then - textadept.io.open(_HOME..'/core/ext/key_commands.lua') + textadept.io.open( + textadept.iconv(_HOME..'/core/ext/key_commands.lua', 'UTF-8', _CHARSET)) end elseif menu_id == ID.RELOAD then textadept.reset() diff --git a/core/file_io.lua b/core/file_io.lua index 12367c47..58494db0 100644 --- a/core/file_io.lua +++ b/core/file_io.lua @@ -22,17 +22,19 @@ recent_files = {} --- -- [Local function] Opens a file or goes to its already open buffer. --- @param filename The absolute path to the file to open. -local function open_helper(filename) - if not filename then return end +-- @param utf8_filename The absolute path to the file to open. Must be UTF-8 +-- encoded. +local function open_helper(utf8_filename) + if not utf8_filename then return end for index, buffer in ipairs(textadept.buffers) do - if filename == buffer.filename then + if utf8_filename == buffer.filename then view:goto_buffer(index) return end end local text + local filename = textadept.iconv(utf8_filename, _CHARSET, 'UTF-8') local f = io.open(filename, 'rb') if f then text = f:read('*all') @@ -57,27 +59,28 @@ local function open_helper(filename) buffer:empty_undo_buffer() buffer.modification_time = lfs.attributes(filename).modification end - buffer.filename = filename + buffer.filename = utf8_filename buffer:set_save_point() - textadept.events.handle('file_opened', filename) + textadept.events.handle('file_opened', utf8_filename) for index, file in ipairs(recent_files) do - if file == filename then + if file == utf8_filename then table.remove(recent_files, index) break end end - recent_files[#recent_files + 1] = filename + recent_files[#recent_files + 1] = utf8_filename end --- -- Opens a list of files. --- @param filenames A '\n' separated list of filenames to open. If none --- specified, the user is prompted to open files from a dialog. --- @usage textadept.io.open(filename) -function open(filenames) - filenames = - filenames or cocoa_dialog('fileselect', { +-- @param utf8_filenames A '\n' separated list of filenames to open. If none +-- specified, the user is prompted to open files from a dialog. These paths +-- must be encoded in UTF-8. +-- @usage textadept.io.open(utf8_encoded_filename) +function open(utf8_filenames) + utf8_filenames = + utf8_filenames or cocoa_dialog('fileselect', { title = locale.IO_OPEN_TITLE, text = locale.IO_OPEN_TEXT, -- in Windows, dialog:get_filenames() is unavailable; only allow single @@ -85,7 +88,7 @@ function open(filenames) ['select-multiple'] = not WIN32 or nil, ['with-directory'] = (buffer.filename or ''):match('.+[/\\]') }) - for filename in filenames:gmatch('[^\n]+') do open_helper(filename) end + for filename in utf8_filenames:gmatch('[^\n]+') do open_helper(filename) end end --- @@ -96,7 +99,9 @@ end function reload(buffer) textadept.check_focused_buffer(buffer) if not buffer.filename then return end - local f, err = io.open(buffer.filename, 'rb') + local utf8_filename = buffer.filename + local filename = textadept.iconv(utf8_filename, _CHARSET, 'UTF-8') + local f = io.open(filename, 'rb') if not f then return end local pos = buffer.current_pos local first_visible_line = buffer.first_visible_line @@ -104,7 +109,7 @@ function reload(buffer) buffer:line_scroll(0, first_visible_line) buffer:goto_pos(pos) buffer:set_save_point() - buffer.modification_time = lfs.attributes(buffer.filename).modification + buffer.modification_time = lfs.attributes(filename).modification f:close() end @@ -118,13 +123,15 @@ function save(buffer) if not buffer.filename then return save_as(buffer) end prepare = _m.textadept.editing.prepare_for_save if prepare then prepare() end - local f, err = io.open(buffer.filename, 'wb') + local utf8_filename = buffer.filename + local filename = textadept.iconv(utf8_filename, _CHARSET, 'UTF-8') + local f, err = io.open(filename, 'wb') if f then local txt, _ = buffer:get_text(buffer.length) f:write(txt) f:close() buffer:set_save_point() - buffer.modification_time = lfs.attributes(buffer.filename).modification + buffer.modification_time = lfs.attributes(filename).modification else textadept.events.error(err) end @@ -134,12 +141,13 @@ end --- -- Saves the current buffer to a file different than its filename property. -- @param buffer The buffer to save. This must be the currently focused buffer. --- @filename The new filepath to save the buffer to. +-- @param utf8_filename The new filepath to save the buffer to. Must be UTF-8 +-- encoded. -- @usage buffer:save_as(filename) -function save_as(buffer, filename) +function save_as(buffer, utf8_filename) textadept.check_focused_buffer(buffer) - if not filename then - filename = + if not utf8_filename then + utf8_filename = cocoa_dialog('filesave', { title = locale.IO_SAVE_TITLE, ['with-directory'] = (buffer.filename or ''):match('.+[/\\]'), @@ -147,10 +155,10 @@ function save_as(buffer, filename) ['no-newline'] = true }) end - if #filename > 0 then - buffer.filename = filename + if #utf8_filename > 0 then + buffer.filename = utf8_filename buffer:save() - textadept.events.handle('file_saved_as', filename) + textadept.events.handle('file_saved_as', utf8_filename) end end @@ -378,14 +386,15 @@ end -- modified outside of Textadept. local function update_modified_file() if not buffer.filename then return end - local filename = buffer.filename + local utf8_filename = buffer.filename + local filename = textadept.iconv(utf8_filename, _CHARSET, 'UTF-8') local attributes = lfs.attributes(filename) if not attributes then return end if buffer.modification_time < attributes.modification then if cocoa_dialog('yesno-msgbox', { title = locale.IO_RELOAD_TITLE, text = locale.IO_RELOAD_TEXT, - ['informative-text'] = string.format(locale.IO_RELOAD_MSG, filename), + ['informative-text'] = string.format(locale.IO_RELOAD_MSG, utf8_filename), ['no-cancel'] = true, ['no-newline'] = true }) == '1' then diff --git a/modules/cpp/commands.lua b/modules/cpp/commands.lua index d1e2fd17..65c3f8af 100644 --- a/modules/cpp/commands.lua +++ b/modules/cpp/commands.lua @@ -12,7 +12,9 @@ if type(keys) == 'table' then local m_editing = _m.textadept.editing keys.cpp = { al = { - m = { textadept.io.open, _HOME..'/modules/cpp/init.lua' }, + m = { textadept.io.open, + textadept.iconv(_HOME..'/modules/cpp/init.lua', + 'UTF-8', _CHARSET) }, }, ['s\n'] = { function() buffer:line_end() diff --git a/modules/cpp/snippets.lua b/modules/cpp/snippets.lua index 4f2c5833..8a4e0291 100644 --- a/modules/cpp/snippets.lua +++ b/modules/cpp/snippets.lua @@ -49,7 +49,7 @@ if type(snippets) == 'table' then lrsi = 'lua_rawseti(%1(lua), %2(-2), %3(1));', lr = 'lua_register(%1(lua), %2(fname), %3(cfunction));', lsf = 'lua_setfield(%1(lua), %2(-2), %3(field));', - lsg = 'lua_setglobal(%1(lua), %2(-2), %3(global));', + lsg = 'lua_setglobal(%1(lua), %2(global));', lst = 'lua_settable(%1(lua), %2(-3));', ltb = 'lua_toboolean(%1(lua), %2(-1))', ltcf = 'lua_tocfunction(%1(lua), %2(-1))', diff --git a/modules/lua/commands.lua b/modules/lua/commands.lua index 47e872e0..8055f470 100644 --- a/modules/lua/commands.lua +++ b/modules/lua/commands.lua @@ -59,7 +59,7 @@ function goto_required() for path in package.path:gmatch('[^;]+') do path = path:gsub('?', file) if lfs.attributes(file) then - textadept.io.open(path) + textadept.io.open(textadept.iconv(path, 'UTF-8', _CHARSET)) break end end @@ -71,7 +71,9 @@ if type(keys) == 'table' then local m_editing = _m.textadept.editing keys.lua = { al = { - m = { textadept.io.open, _HOME..'/modules/lua/init.lua' }, + m = { textadept.io.open, + textadept.iconv(_HOME..'/modules/lua/init.lua', + 'UTF-8', _CHARSET) }, g = { goto_required }, }, ['s\n'] = { try_to_autocomplete_end }, diff --git a/modules/textadept/run.lua b/modules/textadept/run.lua index c45d9019..594b4657 100644 --- a/modules/textadept/run.lua +++ b/modules/textadept/run.lua @@ -16,11 +16,11 @@ module('_m.textadept.run', package.seeall) -- * %(filename) The name of the file including extension. -- * %(filename_noext) The name of the file excluding extension. function execute(command) - local filepath = buffer.filename + local filepath = textadept.iconv(buffer.filename, _CHARSET, 'UTF-8') local filedir, filename = filepath:match('^(.+[/\\])([^/\\]+)$') local filename_noext = filename:match('^(.+)%.') command = command:gsub('%%%b()', { - ['%(filepath)'] = filepath, + ['%(filepath)'] = filepath, _CHARSET, 'UTF-8', ['%(filedir)'] = filedir, ['%(filename)'] = filename, ['%(filename_noext)'] = filename_noext, @@ -31,7 +31,7 @@ function execute(command) local out = p:read('*all') p:close() lfs.chdir(current_dir) - textadept.print('> '..command..'\n'..out) + textadept.print(textadept.iconv('> '..command..'\n'..out, 'UTF-8', _CHARSET)) buffer:goto_pos(buffer.length) end @@ -136,15 +136,16 @@ function goto_error(pos, line_num) local captures = { line:match(error_detail.pattern) } if #captures > 0 then local lfs = require 'lfs' - local filename = captures[error_detail.filename] + local utf8_filename = captures[error_detail.filename] + local filename = textadept.iconv(utf8_filename, _CHARSET, 'UTF-8') if lfs.attributes(filename) then - textadept.io.open(filename) + textadept.io.open(utf8_filename) _m.textadept.editing.goto_line(captures[error_detail.line]) local msg = captures[error_detail.message] if msg then buffer:call_tip_show(buffer.current_pos, msg) end else error(string.format( - locale.M_TEXTADEPT_RUN_FILE_DOES_NOT_EXIST, filename)) + locale.M_TEXTADEPT_RUN_FILE_DOES_NOT_EXIST, utf8_filename)) end break end diff --git a/src/lua_interface.c b/src/lua_interface.c index 29d22e54..94dbb74d 100644 --- a/src/lua_interface.c +++ b/src/lua_interface.c @@ -68,6 +68,7 @@ static int l_cf_ta_buffer_new(lua_State *lua), l_cf_ta_goto_window(lua_State *lua), l_cf_view_goto_buffer(lua_State *lua), l_cf_ta_gtkmenu(lua_State *lua), + l_cf_ta_iconv(lua_State *lua), l_cf_ta_reset(lua_State *lua), l_cf_ta_quit(lua_State *lua), l_cf_pm_focus(lua_State *lua), @@ -135,6 +136,7 @@ bool l_init(int argc, char **argv, bool reinit) { l_cfunc(lua, l_cf_ta_goto_window, "goto_view"); l_cfunc(lua, l_cf_ta_get_split_table, "get_split_table"); l_cfunc(lua, l_cf_ta_gtkmenu, "gtkmenu"); + l_cfunc(lua, l_cf_ta_iconv, "iconv"); l_cfunc(lua, l_cf_ta_reset, "reset"); l_cfunc(lua, l_cf_ta_quit, "quit"); l_mt(lua, "_textadept_mt", l_ta_mt_index, l_ta_mt_newindex); @@ -151,6 +153,10 @@ bool l_init(int argc, char **argv, bool reinit) { lua_pushboolean(lua, 1); lua_setglobal(lua, "MAC"); #endif + const char *charset = 0; + g_get_charset(&charset); + lua_pushstring(lua, charset); + lua_setglobal(lua, "_CHARSET"); if (l_load_script("core/init.lua")) { lua_getglobal(lua, "textadept"); @@ -1477,6 +1483,18 @@ static int l_cf_ta_gtkmenu(lua_State *lua) { return 1; } +static int l_cf_ta_iconv(lua_State *lua) { + const char *text = luaL_checkstring(lua, 1); + const char *to = luaL_checkstring(lua, 2); + const char *from = luaL_checkstring(lua, 3); + char *converted = g_convert(text, -1, to, from, NULL, NULL, NULL); + if (converted) { + lua_pushstring(lua, const_cast<char*>(converted)); + g_free(converted); + } else luaL_error(lua, "Conversion failed"); + return 1; +} + static int l_cf_ta_reset(lua_State *lua) { l_handle_event("resetting"); l_init(0, NULL, true); |