Re: Spellchecker

From: anton <averbit....at.yandex.ru>
Date: Sun, 12 Jun 2011 13:58:56 -0700 (PDT)

I've written a very simple spellchecker module based on Hunspell and
Lua binding from Michal.
(see below)

In order to use it you need to compile spell.cpp from
    https://github.com/mkottman/luaspell
linking it against the hunspell library (libhunspell-1.2.a on my
SuSe),
add it to your cpath and add the dictionaries (see code)

Sorry for mess, I'm not a programmer so don't have a github account.

Please let me know if you find errors. Hope it'll be of some use.

----- init.lua

---
-- The spellchecker module
-- based on Hunspell
-- and Lua Hunspell binding from Michal Kottman
--
-- The functionality is divided in two main parts
-- * marking of misspelled words
-- * suggestions providing
--
--
-- in order to use the functionality directly
-- rather the through events mechanism you need to modify
-- function signatures in the following way
-- spellcheck_line(luaState, line_num)
-- otherwise call spellcheck_line(number)
-- will produce an error message
module('_m.spellchecker', package.seeall)
-- hunspell functionality is provided
-- by spell.so library
-- from Lua Hunspell Binding
local spell = require 'spell'
assert(spell, 'spell not loaded')
assert(type(spell) == "function", 'spell is not a function')
local L = _G.locale.localize
--- module variables
-- speller: container for Hunspell class
local speller
-- dic: table holds paths to dictionaries
local dic = {['en_US']={'/usr/share/myspell/en_US.aff','/usr/share/
myspell/en_US.dic'},}
-- DEFAULT_LANG: key in the dic table for default language
local DEFAULT_LANG = 'en_US'
-- indicator style index for misspelled words
local INDIC_SPELLCHECKER
local LIST_TYPE_SPELLCHECKER = 2
-- handler indices for disconnection of events
local handler_index_spelling
local handler_index_suggestions
--- dictionary manipulations
function add_dictionary(dic_name, aff_filename, dic_filename)
  dic[dic_name] = {aff_filename , dic_filename}
end
function set_dictionary(dic_name)
  speller = spell( dic[dic_name][1] , dic[dic_name][2])
end
--- functionality from Hunspell
-- return true if word is correctly spelled
function is_correct(word)
        return speller:spell(word)
end
-- returns array of suggestions
function suggest(word)
  return speller:suggest(word)
end
--- marking functionality
local function set_indicator_properties()
   INDIC_SPELLCHECKER = 3
   -- Squiggle
   buffer.indic_style[INDIC_SPELLCHECKER] = 2
   -- red color
   buffer.indic_fore[INDIC_SPELLCHECKER] = 0x0000FF
end
local function mark_misspelled(word_start, word_end)
   -- save current indicator
   local saved_indicator_current = buffer.indicator_current
   -- make spell indicator active
   buffer.indicator_current = INDIC_SPELLCHECKER
   -- mark the word
   buffer:indicator_fill_range(word_start, word_end - word_start)
   -- restore default setting
   buffer.indicator_current = saved_indicator_current
end
local function unmark_misspelled(word_start, word_end)
   -- save current indicator
   local saved_indicator_current = buffer.indicator_current
   -- and make spell indicator active
   buffer.indicator_current = INDIC_SPELLCHECKER
   -- mark the word
   buffer:indicator_clear_range(word_start, word_end - word_start)
   -- restore default settings
   buffer.indicator_current = saved_indicator_current
end
--- interaction with lexers
-- which lexer styles are accepted
local function accept_character(pos)
  if buffer:get_style_name(buffer.style_at[pos]) == 'default' then
    return true
  else
    return false
  end
end
-- word is accepted if all its characters are accepted
local function accept_word(word_start, word_end)
  -- if we have multiple delimiters like two spaces
  if word_start >= word_end then
    return false
  end
  local is_accepted = true
  -- word_end correspond to first character after the word
  for _= word_start, word_end - 1 do
     is_accepted = is_accepted and accept_character(_)
  end
  return is_accepted
end
function spellcheck_line(line_num)
  local line_start = buffer:position_from_line(line_num)
  local line_end   = buffer.line_end_position[line_num]
  local word_start, word_end
  if ((line_start ~= -1) and (line_end > line_start)) then
    unmark_misspelled(line_start,line_end)
    word_start = line_start
    while word_start < line_end do
      word_start = buffer:word_start_position(word_start,true)
      word_end = buffer:word_end_position(word_start,true)
      if (accept_word(word_start, word_end)
          and not is_correct(buffer:text_range(word_start,word_end)))
then
        mark_misspelled(word_start,word_end)
      end
      word_start = word_end + 1
    end
  end
end
function spellcheck_lines(first_line, last_line)
  for _ = first_line, last_line do
      spellcheck_line(_)
  end
end
function suggest_list()
  local s,e = buffer:word_start_position(buffer.current_pos,true),
               buffer:word_end_position(buffer.current_pos,true)
  local word = buffer:text_range(s,e)
  if (not is_correct(word)) then
    -- create list string
    local list = speller:suggest(word)
    list_string = ''
    for _,v in ipairs(list) do
      list_string = list_string..v..' '
    end
    -- delete space(s) at the end
    list_string = string.gsub(list_string,'%s+$','')
    buffer:user_list_show(LIST_TYPE_SPELLCHECKER,list_string)
  end
end
function replace_word(wParam,text)
  if wParam == LIST_TYPE_SPELLCHECKER then
    -- select the word
    local s,e = buffer:word_start_position(buffer.current_pos,'%a'),
                 buffer:word_end_position(buffer.current_pos,'%a')
    buffer:set_sel(s,e)
    -- replace it with text
    buffer:replace_sel(text)
  end
end
--- enabling/disabling events
function enable_spellcheck()
  handler_index_spelling = events.connect('update_ui',
                                          function()
 
spellcheck_lines(buffer.first_visible_line,
                                            buffer.first_visible_line
+ buffer.lines_on_screen +1)
                                          end)
  events.emit('update_ui')
end
function disable_spellcheck()
  unmark_misspelled(0, buffer.line_end_position[buffer.line_count -
1])
  events.disconnect('update_ui', handler_index_spelling)
end
function enable_suggestions()
  handler_index_suggestions = events.connect('user_list_selection',
replace_word)
end
function disable_suggestions()
  events.disconnect('user_list_selection', handler_index_suggestions)
end
set_indicator_properties()
set_dictionary(DEFAULT_LANG)
assert(speller, 'dict not loaded')
enable_spellcheck()
enable_suggestions()
Received on Sun 12 Jun 2011 - 16:58:56 EDT

This archive was generated by hypermail 2.2.0 : Thu 08 Mar 2012 - 12:09:44 EST