Skip to content

Commit

Permalink
Added line numbers and split up code
Browse files Browse the repository at this point in the history
  • Loading branch information
curlpipe committed Aug 27, 2020
1 parent 38eb1db commit 8655a6c
Show file tree
Hide file tree
Showing 10 changed files with 183 additions and 86 deletions.
49 changes: 49 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ lto = true
termion = "1"
unicode-segmentation = "1"
unicode-width = "0"
regex = "1"
20 changes: 20 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Config.rs - In charge of storing configuration information
use termion::color;

// Set up background colours
pub const BG: color::Bg<color::Rgb> = color::Bg(color::Rgb(40, 42, 54));
pub const STATUS_BG: color::Bg<color::Rgb> = color::Bg(color::Rgb(68, 71, 90));
pub const RESET_BG: color::Bg<color::Reset> = color::Bg(color::Reset);

// Set up foreground colours
pub const FG: color::Fg<color::Rgb> = color::Fg(color::Rgb(255, 255, 255));
pub const STATUS_FG: color::Fg<color::Rgb> = color::Fg(color::Rgb(80, 250, 123));
pub const RESET_FG: color::Fg<color::Reset> = color::Fg(color::Reset);

// For holding the tab width (how many spaces in a tab)
pub const TAB_WIDTH: usize = 4;

// Line numbers
pub const LINE_NUMBER_FG: color::Fg<color::Rgb> = color::Fg(color::Rgb(68, 71, 90));
pub const LINE_NUMBER_PADDING: usize = 1;

8 changes: 8 additions & 0 deletions src/document.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// Document.rs - For managing external files
use crate::config::LINE_NUMBER_PADDING; // Config stuff
use crate::Row; // The Row struct
use std::fs; // For managing file reading and writing

Expand All @@ -7,6 +8,7 @@ pub struct Document {
pub rows: Vec<Row>, // For holding the contents of the document
pub path: String, // For holding the path to the document
pub name: String, // For holding the name of the document
pub line_offset: usize, // For holding a line number offset
}

// Add methods to the document struct
Expand All @@ -17,6 +19,7 @@ impl Document {
rows: vec![Row::from("")],
name: String::from("[No name]"),
path: String::new(),
line_offset: 2,
}
}
pub fn open(path: &str) -> Option<Self> {
Expand All @@ -29,6 +32,7 @@ impl Document {
rows: file.iter().map(|row| Row::from(*row)).collect(),
name: path.to_string(),
path: path.to_string(),
line_offset: 2,
})
} else {
// File doesn't exist
Expand All @@ -45,9 +49,13 @@ impl Document {
rows: vec![Row::from("")],
name: path.to_string(),
path: path.to_string(),
line_offset: 2,
}
}
}
pub fn recalculate_offset(&mut self) {
self.line_offset = self.rows.len().to_string().len() + LINE_NUMBER_PADDING;
}
pub fn save(&self) -> std::io::Result<()> {
// Save a file
fs::write(&self.path, self.render())
Expand Down
49 changes: 19 additions & 30 deletions src/editor.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
// Editor.rs - Controls the editor and brings everything together
use crate::{Document, Row, Terminal}; // Bringing in all the structs
use crate::config::*; // Bring in the configuration values
use crate::util::title; // Bring in the title utility for text formatting
use std::time::Duration; // For implementing an FPS cap
use std::{cmp, env, thread}; // Managing threads, arguments and comparisons.
use termion::event::Key; // For reading Keys and shortcuts
Expand All @@ -10,18 +12,6 @@ use unicode_width::UnicodeWidthStr; // For calculating unicode character widths
// Get the current version of Ox
const VERSION: &str = env!("CARGO_PKG_VERSION");

// Set up some colours
const BG: color::Bg<color::Rgb> = color::Bg(color::Rgb(40, 42, 54));
const STATUS_BG: color::Bg<color::Rgb> = color::Bg(color::Rgb(68, 71, 90));
const RESET_BG: color::Bg<color::Reset> = color::Bg(color::Reset);

const FG: color::Fg<color::Rgb> = color::Fg(color::Rgb(255, 255, 255));
const STATUS_FG: color::Fg<color::Rgb> = color::Fg(color::Rgb(80, 250, 123));
const RESET_FG: color::Fg<color::Reset> = color::Fg(color::Reset);

// For holding the tab width (how many spaces in a tab)
const TAB_WIDTH: usize = 4;

// Enum for the kinds of status messages
enum Type {
Error,
Expand Down Expand Up @@ -384,8 +374,9 @@ impl Editor {
}
if line.length() > self.cursor.x + self.offset.x {
// If the proposed move is within the current line length
let indicator1 =
self.cursor.x == self.term.width.saturating_sub(jump as u16) as usize;
let indicator1 = self.cursor.x == self.term.width.saturating_sub(
(self.doc.line_offset + jump + 1) as u16
) as usize;
let indicator2 = self.cursor.x == self.term.width.saturating_sub(1) as usize;
if indicator1 || indicator2 {
self.offset.x = self.offset.x.saturating_add(jump);
Expand Down Expand Up @@ -442,9 +433,11 @@ impl Editor {
}
self.offset.x = line
.length()
.saturating_add(jump)
.saturating_add(jump + self.doc.line_offset + 1)
.saturating_sub(self.term.width as usize);
self.cursor.x = self.term.width.saturating_sub(jump as u16) as usize;
self.cursor.x = self.term.width.saturating_sub(
(self.doc.line_offset + jump + 1) as u16
) as usize;
} else {
self.cursor.x = line.length();
}
Expand Down Expand Up @@ -494,9 +487,10 @@ impl Editor {
fn update(&mut self) {
// Move the cursor and render the screen
self.term.goto(&Position { x: 0, y: 0 });
self.doc.recalculate_offset();
self.render();
self.term.goto(&Position {
x: self.cursor.x,
x: self.cursor.x.saturating_add(self.doc.line_offset + 1),
y: self.cursor.y,
});
self.term.flush();
Expand Down Expand Up @@ -596,24 +590,19 @@ impl Editor {
frame.push(self.welcome_message("Ctrl + S: Save ", STATUS_FG));
} else if row == (self.term.height / 4).saturating_add(5) && self.show_welcome {
frame.push(self.welcome_message("Ctrl + W: Save as", STATUS_FG));
} else if let Some(row) = self.doc.rows.get(self.offset.y + row as usize) {
} else if let Some(line) = self.doc.rows.get(self.offset.y + row as usize) {
// Render lines of code
frame.push(
self.add_background(&row.render(self.offset.x, self.term.width as usize)),
);
frame.push(self.add_background(&line.render(
self.offset.x,
self.term.width as usize,
self.offset.y + row as usize,
self.doc.line_offset
)));
} else {
// Render empty lines
frame.push(self.add_background("~"));
frame.push(format!("{}{}{}", LINE_NUMBER_FG, self.add_background("~"), RESET_FG));
}
}
print!("{}", frame.join("\r\n"));
}
}

fn title(c: &str) -> String {
if let Some(f) = c.chars().next() {
f.to_uppercase().collect::<String>() + &c[1..]
} else {
String::new()
}
}
2 changes: 2 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ mod document;
mod editor;
mod row;
mod terminal;
mod config;
mod util;

use document::Document;
use editor::{Editor, Position};
Expand Down
71 changes: 17 additions & 54 deletions src/row.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Row.rs - Handling the rows of a document
use unicode_segmentation::UnicodeSegmentation; // For splitting up unicode
use unicode_width::{UnicodeWidthChar, UnicodeWidthStr}; // Getting width of unicode characters
use unicode_width::UnicodeWidthStr; // Getting width of unicode strings
use crate::config::{LINE_NUMBER_FG, LINE_NUMBER_PADDING, RESET_FG}; // Config stuff
use crate::util::{trim_start, trim_end, no_ansi_len}; // Bring in the utilities

// Ensure we can use the Clone trait to copy row structs for manipulation
#[derive(Clone)]
Expand All @@ -20,9 +22,21 @@ impl From<&str> for Row {

// Add methods to the Row struct / class
impl Row {
pub fn render(&self, start: usize, end: usize) -> String {
pub fn render(&self, start: usize, end: usize, index: usize, offset: usize) -> String {
// Render the row by trimming it to the correct size
trim_end(&trim_start(&self.string, start), end)
let index = index.saturating_add(1);
let post_padding = offset.saturating_sub(index.to_string().len() + LINE_NUMBER_PADDING);
let line_number = format!(
"{}{}{}{}{}",
LINE_NUMBER_FG,
" ".repeat(post_padding),
index,
" ".repeat(LINE_NUMBER_PADDING.saturating_add(1)),
RESET_FG,
);
let line_number_len = no_ansi_len(&line_number);
let body = trim_end(&trim_start(&self.string, start), end.saturating_sub(line_number_len));
line_number + &body
}
pub fn length(&self) -> usize {
// Get the current length of the row
Expand Down Expand Up @@ -75,54 +89,3 @@ impl Row {
self.string = before + &after;
}
}

fn trim_start(text: &str, start: usize) -> String {
// Create a special vector with spaces inserted for trimming
let mut widths = Vec::new();
for i in text.chars() {
widths.push(UnicodeWidthChar::width(i).unwrap());
}
let chars: Vec<char> = text.chars().collect();
let mut result = Vec::new();
let mut count = 0;
for i in 0..chars.len() {
for c in 0..widths[i] {
if c == 0 {
result.push(chars[i].to_string());
} else if count <= start {
result.push(" ".to_string());
}
count += 1;
}
}
if let Some(result) = result.get(start..) {
result.join("")
} else {
String::new()
}
}

fn trim_end(text: &str, end: usize) -> String {
// Trim a string with unicode in it to fit into a specific length
let mut widths = Vec::new();
for i in text.chars() {
widths.push(UnicodeWidthChar::width(i).unwrap());
}
let chars: Vec<char> = text.chars().collect();
let mut result = Vec::new();
let mut length = 0;
for i in 0..chars.len() {
let chr = chars[i];
let wid = widths[i];
if length == end {
return result.join("");
} else if length + wid <= end {
result.push(chr.to_string());
length += wid;
} else if length + wid > end {
result.push(" ".to_string());
return result.join("");
}
}
result.join("")
}
3 changes: 2 additions & 1 deletion src/terminal.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Terminal.rs - Handling low level terminal operations
use crate::Position; // Allow use and handling of positions
use crate::util::no_ansi_len; // To strip ansi values
use std::io::{stdout, Stdout, Write}; // For writing to the stdout
use termion::raw::{IntoRawMode, RawTerminal}; // To access raw mode
use termion::screen::AlternateScreen; // To render to a separate screen
Expand Down Expand Up @@ -50,7 +51,7 @@ impl Terminal {
}
pub fn align_left(&self, text: &str) -> String {
// Align items to the left
let length = UnicodeWidthStr::width(text);
let length = no_ansi_len(text);
let padding = (self.width as usize).saturating_sub(length);
" ".repeat(padding as usize)
}
Expand Down
Loading

0 comments on commit 8655a6c

Please sign in to comment.