aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/edit_display.erl
diff options
context:
space:
mode:
Diffstat (limited to 'src/edit_display.erl')
-rw-r--r--src/edit_display.erl154
1 files changed, 154 insertions, 0 deletions
diff --git a/src/edit_display.erl b/src/edit_display.erl
new file mode 100644
index 0000000..e732c62
--- /dev/null
+++ b/src/edit_display.erl
@@ -0,0 +1,154 @@
+%%%----------------------------------------------------------------------
+%%% File : edit_display.erl
+%%% Author : Luke Gorrie <luke@bluetail.com>
+%%% Purpose : Editor display process: talks to curses
+%%% Created : 16 Sep 2000 by Luke Gorrie <luke@bluetail.com>
+%%%----------------------------------------------------------------------
+
+-module(edit_display).
+-author('luke@bluetail.com').
+
+-include_lib("ermacs/include/edit.hrl").
+
+-compile(export_all).
+%%-export([Function/Arity, ...]).
+
+draw_window(Window) when Window#window.minibuffer == true,
+ Window#window.status_text /= undefined ->
+ ?EDIT_TERMINAL:move_to(0, Window#window.y),
+ draw_line(Window#window.status_text),
+ Window#window{status_text=undefined};
+draw_window(Window) ->
+ try_update(Window).
+
+try_update(Window) ->
+ Buf = Window#window.buffer,
+ PointMax = edit_buf:point_max(Buf),
+ DStart = edit_buf:mark_pos(Buf, Window#window.start_mark),
+ Scan = edit_lib:beginning_of_line_pos(Buf, DStart),
+ Point = edit_buf:mark_pos(Buf, point),
+ Chars = (?EDIT_TERMINAL:width() * ?EDIT_TERMINAL:height()) * 4, %% FIXME
+ Text = edit_buf:get_region(Buf, Scan, min(PointMax, Scan + Chars)),
+ ?EDIT_TERMINAL:move_to(0, Window#window.y),
+ Rows = edit_window:text_lines(Window),
+ Prefix = Window#window.prefix,
+ PLen = length(Prefix),
+ PAcc = lists:reverse(Prefix),
+ case try_update_loop(Text,Rows,Scan,PLen,0,Point,undefined,PAcc) of
+ {X, Y} ->
+ %% draw mode line
+ draw_modeline(Window),
+ TrimX = edit_lib:min(X, Window#window.width - 1),
+ ?EDIT_TERMINAL:move_to(TrimX, Y + Window#window.y),
+ Window;
+ undefined ->
+ %% The point wasn't inside the area we drew, so we
+ %% recenter the display with the point in the middle and
+ %% then draw again.
+ try_update(recenter_window(Window))
+ end.
+
+%% Returns the location of the point in a tuple {X, Y}, or undefined
+%% if it wasn't in the area drawn.
+
+try_update_loop(Text, NRows, Scan, Col, Row, Point, PointXY, Acc)
+ when Scan == Point,
+ PointXY == undefined ->
+ try_update_loop(Text,NRows,Scan,Col,Row,Point,{Col, Row},Acc);
+try_update_loop([$\n|T], NRows, Scan, Col, Row, Point, PointXY, Acc) ->
+ draw_line(lists:reverse(Acc)),
+ ?EDIT_TERMINAL:newline(),
+ NextRow = Row+1,
+ if NextRow == NRows ->
+ PointXY;
+ true ->
+ try_update_loop(T,NRows,Scan+1,0,Row+1,Point,PointXY, [])
+ end;
+try_update_loop([$\t|T], NRows, Scan, Col, Row, Point, PointXY, Acc) ->
+ Size = 8 - (Col rem 8),
+ Tab = lists:duplicate(Size, $ ),
+ try_update_loop(T,NRows,Scan+1,Col+Size,Row,Point,PointXY,Tab++Acc);
+try_update_loop([H|T], NRows, Scan, Col, Row, Point, PointXY, Acc) ->
+ try_update_loop(T,NRows,Scan+1,Col+1,Row,Point,PointXY,[H|Acc]);
+try_update_loop([], NRows, Scan, Col, Row, Point, PointXY, Acc) ->
+ draw_line(lists:reverse(Acc)),
+ RemainingRows = NRows - Row,
+ %% draw empty lines until the end
+ dotimes(fun() -> draw_line([]),
+ ?EDIT_TERMINAL:newline()
+ end,
+ RemainingRows),
+ PointXY.
+
+draw_line(L) ->
+ Wth = ?EDIT_TERMINAL:width(),
+ Str = trunc_line(L, Wth),
+ ?EDIT_TERMINAL:put_string(L),
+ ?EDIT_TERMINAL:erase_to_eol().
+
+trunc_line([H], 1) -> [H];
+trunc_line(_, 1) -> [$$];
+trunc_line([H|T], N) -> [H|trunc_line(T, N-1)];
+trunc_line([], _) -> [].
+
+draw_modeline(Window) when Window#window.minibuffer == true ->
+ ok;
+draw_modeline(Window) ->
+ Buffer = Window#window.buffer,
+ Where = modeline_where(Window, Buffer),
+ Text = lists:flatten(
+ io_lib:format("--:?? ~s (~s) ~s",
+ [atom_to_list(Buffer),
+ (edit_buf:get_mode(Buffer))#mode.name,
+ Where])),
+ ?EDIT_TERMINAL:font_reverse(),
+ ?EDIT_TERMINAL:move_to(0, Window#window.y +
+ edit_window:physical_lines(Window) - 1),
+ draw_line(Text),
+ ?EDIT_TERMINAL:font_normal().
+
+modeline_where(Window, Buffer) ->
+ case edit_buf:get_size(Buffer) of
+ 0 ->
+ "ALL";
+ BSize ->
+ Start = edit_buf:mark_pos(Buffer, Window#window.start_mark),
+ Percentage = trunc(Start * 100 / BSize),
+ io_lib:format("~p%", [Percentage])
+ end.
+
+%% Update the display_start of a window so that it presents the point
+%% in the middle of the screen.
+recenter_window(Window) ->
+ Buf = Window#window.buffer,
+ Height = edit_window:text_lines(Window),
+ Pos = backward_lines(Buf, trunc(Height / 2)),
+ edit_buf:move_mark(Buf, Window#window.start_mark, Pos),
+ Window.
+
+backward_lines(Buf, N) ->
+ StartPos = edit_lib:beginning_of_line_pos(Buf),
+ edit_buf:walk_backward(Buf,
+ fun(X) -> back_lines(X, N, StartPos) end,
+ StartPos).
+
+back_lines(finish, N, Pos) ->
+ {result, 1};
+back_lines($\n, N, Pos) ->
+ if
+ N == 1 ->
+ {result, Pos};
+ true ->
+ {more, fun(New) -> back_lines(New, N-1, Pos-1) end}
+ end;
+back_lines(_, N, Pos) ->
+ {more, fun(New) -> back_lines(New, N, Pos-1) end}.
+
+dotimes(Fun, 0) ->
+ true;
+dotimes(Fun, N) when integer(N), N > 0 ->
+ Fun(),
+ dotimes(Fun, N-1).
+
+min(X, Y) when X < Y -> X;
+min(X, Y) -> Y.