wxRuby Editor - More bug fixes and Scintilla text slinging


Squashing Bugs

As you people might know I spent last week in the BKK office. It was me and my laptop with Ubuntu and a seldom used Eclipse + Aptana environment for the duration. Aptana breaks like a brittle twig (I had upgraded my JRE and I suppose Aptana didn’t like that, something with Swing was not ok, I have since then solved the problem by updating Aptana with a 187MB!? patch, at the time it happened I decided to give it a rest though).

I decided to try out the Pico Editor instead but editing PHP, HTML, CSS and Javascript instead of Pico Lisp. As soon as I tried to paste something the thing crashed hard though, what was happening?

From the old scintilla.rb:

def styleWithPos(start_pos, end_pos)
  start_line = self.line_from_position(start_pos)
  end_line = self.line_from_position(end_pos)
  self.start_styling(start_pos, 31)
  @cur_lexer.startStyling(self, start_line, end_line)
  @cur_lexer.setFolding(self, start_pos, end_pos - start_pos)
end

StartStyling, wtf? All modes except Pico and HTML lack that function since we rely on inbuilt C++ lexers to do the job for us there instead. Oops… It looks like this now:

def styleWithPos(start_pos, end_pos)
  start_line = self.line_from_position(start_pos)
  end_line = self.line_from_position(end_pos)
  self.start_styling(start_pos, 31)
  if(@cur_lexer.lex_num == STC_LEX_CONTAINER)
    @cur_lexer.startStyling(self, start_line, end_line)
    @cur_lexer.setFolding(self, start_pos, end_pos - start_pos)
  end
end

Much better, if a mode runs with STC_LEX_CONTAINER it means it must have a custom styling logic, perfect, bug squashed.

Today I discovered another annoying thing unique to Pico Lisp, when doing for instance:

(func "hello" '((Im) "a lambda")
  (prog...)

And auto indenting I want it to look like above, instead I got:

(func "hello" '((Im) "a lambda")
                      (prog...)

It seems like the the logic responsible for this look:

'((X)
  ("Here we do something with X"))

And not this look:

'((X)
    ("Here we do something with X"))

Was responsible for this failure, well we only live once and I don’t have time for splitting hairs, so I guess I have to live with the latter look. The indenting logic in pico.rb used to look like this:

def indentLine(sci, line_nbr, cur_pos, single = true)
  line_ind = 0
  if line_nbr > 0
    above_line = sci.get_line(line_nbr - 1)
    if above_line.strip.length > 0
      par_count = self.parensCount(above_line)
      stack     = par_count > 0 ? "(" * (par_count + 1) : false
      if(stack && above_line.index(stack) != nil)
        line_ind = above_line.index(stack) + par_count
      else
        if par_count == 0
          line_ind = above_line.index(/\S/)
        else
          line_ind = sci.get_column(self.findParPos(sci, cur_pos, "left", 2)) + 2
        end
      end
    end
  end
  sci.set_line_indentation(line_nbr, line_ind)
  sci.goto_pos(sci.position_from_line(line_nbr) + line_ind) if single
end

It now looks like this:

def indentLine(sci, line_nbr, cur_pos, single = true)
  line_ind = 0
  if line_nbr > 0
    above_line = sci.get_line(line_nbr - 1)
    if above_line.strip.length > 0
      par_count = self.parensCount(above_line)
      if par_count == 0
        line_ind = sci.get_line(line_nbr - 1).index(/\S/)
      else
        line_ind = sci.get_column(self.findParPos(sci, cur_pos, "left", 2)) + 2
      end
    end
  end
  sci.set_line_indentation(line_nbr, line_ind)
  sci.goto_pos(sci.position_from_line(line_nbr) + line_ind) if single
end

As you can see the logic responsible for the silly prettying of multi-line lambdas is now gone. Since we are now also using line_ind = sci.get_line(line_nbr - 1).index(/\S/) instead of line_ind = above_line.index(/\S/) this bugged out formatting:

(func
  "nice" '(lambda)
     "cool" '(lambda))

Will look straight:

(func
  "nice" '(lambda)
  "cool" '(lambda))

 

Implementing “Outer Delete” feature

Imagine a situation where the caret is positioned to match brackets like this:

(func
  (prog
    (prog2)))

When you for instance press ctrl-r you want the outermost expression to be removed so the expression looks like this:

  (prog
    (prog2))

This situation happens quite often and needed a solution. The Pico class now has the following method which is called with ctrl-r:

def remMatch(sci)
  self.selMatch(sci)
  expr = sci.get_selected_text
  if expr
    expr = expr.slice(1, expr.length - 2).sub(/^[^\(]+/, '') if expr.length > 2
    sci.clear
    sci.insert_text(sci.get_current_pos, expr)
  end
end

We begin with selecting the expression to work with through selMatch, then we store the selected text in expr. If something got selected (I’m not certain that this check is needed but just to be on the safe side) we slice it by removing the first character ‘(’ and the last character ‘)’, the expression will now look like this:

func
  (prog
    (prog2))

The sub(/^[^\(]+/, ”) replacement will take us the rest of the way to:

(prog
   (prog2))

Finally we clear (sci.clear) the original selection and replace it (sci.insert_text) with the above expression.

The source has of course been updated.

Related Posts

Tags: , , ,