162 lines
3.4 KiB
Julia
162 lines
3.4 KiB
Julia
#############
|
|
# ROW #
|
|
#############
|
|
|
|
"""Holds file true data and render data"""
|
|
mutable struct Row
|
|
"file data, a row of text"
|
|
chars::String
|
|
|
|
"a row of text as rendered on screen"
|
|
render::String
|
|
end
|
|
|
|
Row(s::String) = Row(s, "")
|
|
|
|
"""Update the `render` string using the `chars` string"""
|
|
function update!(row::Row)
|
|
# Count the number of tabs
|
|
tabs = 0
|
|
for c in row.chars
|
|
c == '\t' && (tabs += 1)
|
|
end
|
|
|
|
# Allocate an array of characters
|
|
updated = Array{Char, 1}(length(row.chars) + tabs*(configGet(:tab_stop)-1))
|
|
|
|
# copy the characters into the updated array
|
|
idx = 1
|
|
for i in 1:length(row.chars)
|
|
|
|
# replace tabs with spaces
|
|
if row.chars[i] == '\t'
|
|
updated[idx] = ' '
|
|
idx += 1
|
|
while idx % configGet(:tab_stop) != 0;
|
|
updated[idx] = ' ';
|
|
idx += 1
|
|
end
|
|
else
|
|
updated[idx] = row.chars[i]
|
|
idx += 1
|
|
end
|
|
|
|
end
|
|
|
|
row.render = join(updated[1:idx-1])
|
|
end
|
|
|
|
"""Convert a cursor position in the document to a rendered cursor position"""
|
|
function renderX(row::Row, cx::Int)
|
|
rx = 1
|
|
for i in 1:cx-1
|
|
# If there is a tab, move the cursor forward to the tab stop
|
|
if row.chars[i] == '\t'
|
|
rx += (configGet(:tab_stop) - 1) - (rx % configGet(:tab_stop))
|
|
end
|
|
rx += 1
|
|
end
|
|
rx
|
|
end
|
|
|
|
|
|
"""opposite of renderX: Convert a render position to a chars position"""
|
|
function charX(row::Row, rx::Int)
|
|
cur_rx = 1
|
|
for cx = 1:length(row.chars)
|
|
if row.chars[cx] == '\t'
|
|
cur_rx += (configGet(:tab_stop) - 1) - (cur_rx % configGet(:tab_stop))
|
|
end
|
|
cur_rx += 1
|
|
|
|
cur_rx > rx && return cx
|
|
end
|
|
cx
|
|
end
|
|
|
|
|
|
"""Insert a char or string into a string"""
|
|
function insert(s::String, i::Int, c::Union{Char,String})
|
|
if s == ""
|
|
string(c)
|
|
else
|
|
string(s[1:i-1], c, s[i:end])
|
|
end
|
|
end
|
|
|
|
"""Delete char from string"""
|
|
function delete(s::String, i::Int)
|
|
i < 1 || i > length(s) && return s
|
|
string(s[1:i-1], s[i+1:end])
|
|
end
|
|
|
|
"""Insert a char into the row at a given location"""
|
|
function insertChar!(row::Row, i::Int, c::Char)
|
|
row.chars = insert(row.chars, i, c)
|
|
update!(row)
|
|
end
|
|
|
|
"""Insert a tab into the row at a given location. Return the number of chars inserted"""
|
|
function insertTab!(row::Row, i::Int)
|
|
num_chars = 1
|
|
t = '\t'
|
|
|
|
# If we are using spaces, move ahead more
|
|
if configGet(:expandtab)
|
|
num_chars = configGet(:tab_stop) - (i % configGet(:tab_stop))
|
|
t = repeat(" ", num_chars)
|
|
end
|
|
|
|
row.chars = insert(row.chars, i, t)
|
|
update!(row)
|
|
|
|
# Used for positioning the cursor
|
|
return num_chars
|
|
end
|
|
|
|
|
|
"""Delete char from row"""
|
|
function deleteChar!(row::Row, i::Int)
|
|
row.chars = delete(row.chars, i)
|
|
update!(row)
|
|
end
|
|
|
|
"""
|
|
Add a row to the end of the document
|
|
initialize the row with the given string
|
|
"""
|
|
function appendRowString(row::Row, str::String)
|
|
row.chars = string(row.chars, str)
|
|
update!(row)
|
|
end
|
|
|
|
|
|
|
|
########
|
|
# ROWS #
|
|
########
|
|
|
|
"""type alias for Array{Row, 1}"""
|
|
Rows = Array{Row, 1}
|
|
|
|
"""delete all rows from a Rows"""
|
|
function clearRows(rows::Rows)
|
|
while length(rows) > 0
|
|
pop!(rows)
|
|
end
|
|
end
|
|
|
|
|
|
"""Add a row to the end of the document"""
|
|
function appendRow(rows::Rows, s::String)
|
|
row = Row(s)
|
|
update!(row)
|
|
push!(rows, row)
|
|
end
|
|
|
|
|
|
"""Convert all ROW data to a single string"""
|
|
function rowsToString(rows::Rows)
|
|
join(map(row -> row.chars, rows), '\n')
|
|
end
|