Curses about libcurse

Z

zimba-tm

------=_Part_6032_7248194.1133577613783
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline

Hello,

I hate curses. Not that much, but it's really not that easy to build
ruby console applications using it.

Are there other libraries I could use instead of libcurses ?

My main complains are :
* you can't access the screen like a character matrix
* i want callbacks (onresize)
* you need to move the cursor where you want to write
* the "window"ing system is not cool
* it really feels like an old-skool C library in ruby

I started overriding the curses library to implement what I think is
nicer (which is subjective). Is anybody interested in this ? Also,
what is so special in the libcurse ? Is it because it supports VT100
that people are still using it ?

The joined file containes the modified curses class plus an class that
demonstrates how to use it (however it doesn't run)

--
Cheers,
zimba

http://zimba.oree.ch

------=_Part_6032_7248194.1133577613783
Content-Type: application/octet-stream; name=interface.rb
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename="interface.rb"

require 'curses'

# curses sanitization
module Curses
@windows = Array.new
def self.windows
@windows
end

class Window

def init(buffer_size = 100, wrap = true)
@buffer = Array.new buffer_size, ''
@buffer_x = 0
@buffer_y = 0
@cursor_x = 0
@cursor_y = 0
@windows = Array.new
@line_wrap = wrap
Curses.windows.push self
end

def [](line_num)
@buffer[line_num]
end

def []=(line_num, line)
# TODO: check if data is in screen
@buffer[line_num] = line
old_setpos(line_num, 0)
if @line_wrap && line.length > maxx
addstr line[0..maxx] + "\n"
addstr line[maxx..line.length]
else
addstr line
end

# fill
addstr " " * (maxx - line.length)
old_setpos(line_num, line.length)
end

def puts(line)
# storage
if @cursor_x == @buffer.length-1
@buffer.pop
@buffer.push line
else
@cursor_x += 1
@buffer[@cursor_x] = line
end
# draw
if @line_wrap && line.length > maxx
addstr line[0..maxx] + "\n"
addstr line[maxx..line.length]
else
addstr line
end
end
alias :<< :puts

def putc(char, y=nil, x=nil)
if y == nil
y = @cursor_y
end
if x == nil
x = @cursor_x
end
diff = @buffer[x].length - y
if diff < 0
@buffer[y] += " " * diff
end
@buffer[y][x] << char
end

alias :putc :addch
alias :gets :getstr
alias :getc :getch

alias :eek:ld_refresh :refresh
def refresh
old_refresh
end

alias :eek:ld_clear :clear
def clear
setpos(0,0)
@buffer.fill('')
super
end

alias :eek:ld_setpos :setpos
def setpos(y, x)
@cursor_y = y
@cursor_x = x
old_setpos y, x
end

alias :eek:ld_move :move
def move(y, x)
setpos(@cursor_y + y, @cursor_x + x)
end

alias :eek:ld_subwin :subwin
def subwin(height, width, top, left)
subwin = old_subwin height, width, top, left
subwin.init
@windows.push subwin
return subwin
end

alias :eek:ld_close :close
def close
@windows.each do |window|
window.close
end
Curses.windows.delete self
Curses.close_screen if Curses.windows.length == 0
old_close
end
end

end

module Interface

class Cursed

def initialize(server)
@server = server

Signal.trap('INT') do
exit
end
end

def run
Curses::init_screen # binds curses to the current interface
Curses::raw # cbreak or raw, allows direct char handling
Curses::noecho # we will manage user output ourselves
# keypad(true) # allow handling of the keypad keys
Curses::nonl

lines = Curses::lines
cols = Curses::cols

# interface setup
@w = Curses::Window.new(lines, cols, 0, 0)
@w.init
@title = @w.subwin(1, cols, 0, 0)
@title[0] = "*** Welcome in zchat ***"
@title.refresh
@main = @w.subwin(lines-3, cols, 1, 0)
@main.scrollok(true)
@main.refresh
@status = @w.subwin(1, cols, lines-2, 0)
@status[0] = @server.hostname + ": " + @server.channel.keys.join(', ')
@status.refresh
@input = @w.subwin(1, cols, lines-1, 0)
@input[0] = ENV['USER']+'@'(e-mail address removed)+'/#test$ '
@input.refresh

@server.channel["#test"].on_read do |line|
@main.puts line
@main.refresh
@input.refresh
end

# keyboard input handling
t = Thread.new do
buffer = ''
line = @input[0]
while true

chr = @input.getc
case chr
when 13 # ?\n
case buffer
when /^ls/
$server['#test'].puts '/NAMES #test'
when /^echo\s/
command = buffer[5..buffer.length-1]
@server['#test'].puts command + "\n" if command.length > 0
when /^join\s/
command = buffer[5..buffer.length-1]
@server.puts '/j ' + command
when '\quit', ':q', 'exit', 'quit'
exit
else
@status[0] = "command not found..."
@status.refresh
end

buffer = ''
@input.setpos(0, 0)
when 279168 # Curses::KEY_LEFT
@input.move(0, -1)
when 279167 # Curses::KEY_RIGHT
@input.move(0, +1)
when ?\C-c
exit
when ?\C-? # Curses::KEY_BACKSPACE
if buffer.length > 1
buffer = buffer[0..buffer.length-2] if buffer.length > 1
@input.move(0, -1)
else
buffer = ''
@input.setpos(0, 0)
end
else
buffer << chr
end

@input[0] = line + buffer
@input.refresh
end
end

t.join
end

def exit
@w.close
puts "Exiting zchat..."
@server.exit
Kernel.exit
end
end

end



------=_Part_6032_7248194.1133577613783--
 
R

Reyn Vlietstra

------=_Part_19452_21180194.1133592585224
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline

http://rubyforge.org/projects/rush

would benefit greatly from some sort of improved text library
 
R

Richard Lyman

Is there something specifically that you've been trying to do but couldn't?

Is it just the quality or speed of development that is annoying you?

I ask only because I'm thinking about writing an Ncurses app, so feel
free to 'dump'.

-Rich
 
Z

zimba-tm

Hi Richard,

in brief, you can do anything with curses. You can write text on the
whole screen, use colors, the mouse. So it's not about technical
missing features.

However, the library makes it hard to do some things. First of all,
the library is seriously lacking in documentation. Just take a look to
the curses stdlib rdoc[1] to have an idea. I couldn't go really
further without looking at the provided examples.

Curses integrates a concept of windows. You set a window with top,
left, width and height. Then everything you write inside won't get out
of that box and it can be scrolled. The idea is pretty neat, but it
suffers some limitations. Because you don't have callbacks, you have
to make a loop to track the different changes (like mouse moves and
term resizes). And because it's not well documented, I found it was
hard to have consistent behavior.

It takes much too long to write a simple GUI.

[1] http://www.ruby-doc.org/stdlib/libdoc/curses/rdoc/classes/Curses.html
 
R

Reyn Vlietstra

------=_Part_28875_5177766.1133687055541
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline

Oh, I missed the replies.

The biggest issue with ruSH is that obviously we need to run existing
console binaries on it.
I ran into issues with things like vi etc. I needed to exit curses before
entering vi, or vi would moan and/or break. That made me introduce the ^
character for all the things that needed to exit curses. (eg. ^vi)

Other commands like say for instance 'ls' needs to be run with popen4 which
grabs the output and writes it to the curses screen, so anything that needs
input immediately hangs.

The other thing is that something like ls --color emits color codes, it's
been a while since I worked on this so my minds a bit sketchy. I was having
issues with the number of colors I could define and the fact that if I
change a color it changes all the colors with that number on the screen ...

errrm, so what I basically need is for curses and the console apps to play
together nicely, surely it's possible ?

Tell me if you cant get ruSH running to look at it, it's quite a mission at
the moment :-o

We ... I need a next gen shell !

Hi Richard,

in brief, you can do anything with curses. You can write text on the
whole screen, use colors, the mouse. So it's not about technical
missing features.

However, the library makes it hard to do some things. First of all,
the library is seriously lacking in documentation. Just take a look to
the curses stdlib rdoc[1] to have an idea. I couldn't go really
further without looking at the provided examples.

Curses integrates a concept of windows. You set a window with top,
left, width and height. Then everything you write inside won't get out
of that box and it can be scrolled. The idea is pretty neat, but it
suffers some limitations. Because you don't have callbacks, you have
to make a loop to track the different changes (like mouse moves and
term resizes). And because it's not well documented, I found it was
hard to have consistent behavior.

It takes much too long to write a simple GUI.

[1] http://www.ruby-doc.org/stdlib/libdoc/curses/rdoc/classes/Curses.html

Is there something specifically that you've been trying to do but couldn't?

Is it just the quality or speed of development that is annoying you?

I ask only because I'm thinking about writing an Ncurses app, so feel
free to 'dump'.

-Rich

--
Cheers,
zimba

http://zimba.oree.ch
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,535
Members
45,007
Latest member
obedient dusk

Latest Threads

Top