Skip to content

Commit

Permalink
Revert "Refactor and fix IRC formatting handling (#360)"
Browse files Browse the repository at this point in the history
This reverts commit 33df77e.
  • Loading branch information
osa1 committed Nov 24, 2021
1 parent b7094c9 commit 8f4d485
Show file tree
Hide file tree
Showing 15 changed files with 166 additions and 625 deletions.
13 changes: 0 additions & 13 deletions ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,19 +103,6 @@ for user input events and a TUI handle to update the TUI. The types are:
| term_input | Input handling (reading events from `stdin`) |
| termbox_simple | Terminal manipulation (drawing) |
| libtiny_common | The "channel name" type |
| libtiny_wire | Parsing IRC message formatting characters (colors etc.) |

### libtiny_logger

Implements logging IRC events (incoming messages, user left/joined etc.) to
user-specified log directory.

#### Dependencies of `libtiny_logger`:

| Dependency | Used for |
| -------------- | ------------- |
| libtiny_common | The "channel name" type |
| libtiny_wire | Filtering out IRC message formatting characters (colors etc.) |

### libtiny_wire

Expand Down
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,15 @@ Thanks to @trevarj for contributing to this release.
tiny. (8061042)
- Minor improvements in logging (d0505f2, bbb4b81)
- `/join` (without arguments) now rejoins the current channel. (#334)
<<<<<<< HEAD
- Handling of IRC formatting characters (colors etc.) in TUI and logger
improved:
- TUI now handles "reset" control character, to reset the text style to the
default.
- Logger now filters out all control characters before writing to the file.
(#360)
- Key bindings can be configured in the config file. See the [wiki
page][key-bindings-wiki] for details. (#328, #336)

[key-bindings-wiki]: https://github.com/osa1/tiny/wiki/Configuring-key-bindings

Expand Down
2 changes: 0 additions & 2 deletions Cargo.lock

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

6 changes: 0 additions & 6 deletions assets/README.md

This file was deleted.

2 changes: 0 additions & 2 deletions assets/crate_deps.dot
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,8 @@ digraph mygraph {
"libtiny_client" -> "libtiny_wire"

"libtiny_logger" -> "libtiny_common"
"libtiny_logger" -> "libtiny_wire"

"libtiny_tui" -> "libtiny_common"
"libtiny_tui" -> "libtiny_wire"
"libtiny_tui" -> "term_input"
"libtiny_tui" -> "termbox_simple"

Expand Down
Binary file modified assets/crate_deps.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 0 additions & 1 deletion crates/libtiny_logger/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,5 @@ edition = "2018"

[dependencies]
libtiny_common = { path = "../libtiny_common" }
libtiny_wire = { path = "../libtiny_wire" }
log = "0.4"
time = "0.1"
2 changes: 0 additions & 2 deletions crates/libtiny_logger/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ use std::rc::Rc;
use time::Tm;

use libtiny_common::{ChanName, ChanNameRef, MsgTarget};
use libtiny_wire::formatting::remove_irc_control_chars;

#[macro_use]
extern crate log;
Expand Down Expand Up @@ -307,7 +306,6 @@ impl LoggerInner {
_highlight: bool,
is_action: bool,
) {
let msg = remove_irc_control_chars(msg);
self.apply_to_target(target, |fd: &mut File, report_err: &dyn Fn(String)| {
let io_ret = if is_action {
writeln!(fd, "[{}] {} {}", strf(&ts), sender, msg)
Expand Down
1 change: 0 additions & 1 deletion crates/libtiny_tui/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ desktop-notifications = ["notify-rust"]

[dependencies]
libtiny_common = { path = "../libtiny_common" }
libtiny_wire = { path = "../libtiny_wire" }
log = "0.4"
notify-rust = { version = "3", optional = true }
serde = { version = "1.0", features = ["derive"] }
Expand Down
4 changes: 2 additions & 2 deletions crates/libtiny_tui/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,10 @@ fn default_max_nick_length() -> usize {

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Style {
/// Termbox fg
/// Termbox fg.
pub fg: u16,

/// Termbox bg
/// Termbox bg.
pub bg: u16,
}

Expand Down
113 changes: 57 additions & 56 deletions crates/libtiny_tui/src/msg_area/line.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
use crate::config::{Colors, Style};
use crate::line_split::{LineDataCache, LineType};

use libtiny_wire::formatting::{parse_irc_formatting, Color, IrcFormatEvent};
use crate::line_split::LineType;
use crate::{
config::{Colors, Style},
line_split::LineDataCache,
utils::translate_irc_control_chars,
};
use std::mem;
use termbox_simple::{self, Termbox};

/// A single line added to the widget. May be rendered as multiple lines on the
Expand All @@ -10,7 +13,6 @@ use termbox_simple::{self, Termbox};
pub(crate) struct Line {
/// Line segments.
segments: Vec<StyledString>,

/// The segment we're currently extending.
current_seg: StyledString,

Expand All @@ -33,7 +35,7 @@ pub(crate) enum SegStyle {
/// of the color list, so make sure to use mod.
NickColor(usize),

// Rest of the styles are from the color scheme
/// A style from the current color scheme.
UserMsg,
ErrMsg,
Topic,
Expand Down Expand Up @@ -76,6 +78,9 @@ impl Default for StyledString {
}
}

// TODO get rid of this
const TERMBOX_COLOR_PREFIX: char = '\x00';

impl Line {
pub(crate) fn new() -> Line {
Line {
Expand All @@ -98,7 +103,7 @@ impl Line {
if self.current_seg.string.is_empty() {
self.current_seg.style = style;
} else if self.current_seg.style != style {
let seg = std::mem::replace(
let seg = mem::replace(
&mut self.current_seg,
StyledString {
string: String::new(),
Expand All @@ -110,36 +115,31 @@ impl Line {
}

fn add_text_inner(&mut self, str: &str) {
for format_event in parse_irc_formatting(str) {
match format_event {
IrcFormatEvent::Bold
| IrcFormatEvent::Italic
| IrcFormatEvent::Underline
| IrcFormatEvent::Strikethrough
| IrcFormatEvent::Monospace => {
// TODO
}
IrcFormatEvent::Text(text) => {
self.current_seg.string.push_str(text);
}
IrcFormatEvent::Color { fg, bg } => {
let style = SegStyle::Fixed(Style {
fg: u16::from(irc_color_to_termbox(fg)),
bg: bg
.map(|bg| u16::from(irc_color_to_termbox(bg)))
.unwrap_or(termbox_simple::TB_DEFAULT),
});

self.set_message_style(style);
}
IrcFormatEvent::ReverseColor => {
if let SegStyle::Fixed(Style { fg, bg }) = self.current_seg.style {
self.set_message_style(SegStyle::Fixed(Style { fg: bg, bg: fg }));
}
}
IrcFormatEvent::Reset => {
self.set_message_style(SegStyle::UserMsg);
}
fn push_color(ret: &mut String, irc_fg: u8, irc_bg: Option<u8>) {
ret.push(TERMBOX_COLOR_PREFIX);
ret.push(0 as char); // style
ret.push(irc_color_to_termbox(irc_fg) as char);
ret.push(
irc_bg
.map(irc_color_to_termbox)
.unwrap_or(termbox_simple::TB_DEFAULT as u8) as char,
);
}
let str = translate_irc_control_chars(str, push_color);
self.current_seg.string.reserve(str.len());

let mut iter = str.chars();
while let Some(char) = iter.next() {
if char == TERMBOX_COLOR_PREFIX {
let st = iter.next().unwrap() as u8;
let fg = iter.next().unwrap() as u8;
let bg = iter.next().unwrap() as u8;
let fg = (u16::from(st) << 8) | u16::from(fg);
let bg = u16::from(bg);
let style = Style { fg, bg };
self.set_message_style(SegStyle::Fixed(style));
} else if char > '\x08' {
self.current_seg.string.push(char);
}
}
}
Expand All @@ -150,6 +150,7 @@ impl Line {
}

pub(crate) fn add_char(&mut self, char: char, style: SegStyle) {
assert_ne!(char, TERMBOX_COLOR_PREFIX);
self.set_message_style(style);
self.current_seg.string.push(char);
}
Expand Down Expand Up @@ -229,28 +230,28 @@ impl Line {

////////////////////////////////////////////////////////////////////////////////

// IRC colors: http://en.wikichip.org/wiki/irc/colors
// Termbox colors: http://www.calmar.ws/vim/256-xterm-24bit-rgb-color-chart.html
// (alternatively just run `cargo run --example colors`)
fn irc_color_to_termbox(irc_color: Color) -> u8 {
fn irc_color_to_termbox(irc_color: u8) -> u8 {
match irc_color {
Color::White => 255,
Color::Black => 16,
Color::Blue => 21,
Color::Green => 46,
Color::Red => 196,
Color::Brown => 88,
Color::Magenta => 93,
Color::Orange => 210,
Color::Yellow => 228,
Color::LightGreen => 154,
Color::Cyan => 75,
Color::LightCyan => 39,
Color::LightBlue => 38,
Color::Pink => 129,
Color::Grey => 243,
Color::LightGrey => 249,
Color::Default => termbox_simple::TB_DEFAULT as u8,
Color::Ansi(ansi_color) => ansi_color,
0 => 15, // white
1 => 0, // black
2 => 17, // navy
3 => 2, // green
4 => 9, // red
5 => 88, // maroon
6 => 5, // purple
7 => 130, // olive
8 => 11, // yellow
9 => 10, // light green
10 => 6, // teal
11 => 14, // cyan
12 => 12, // awful blue
13 => 13, // magenta
14 => 8, // gray
15 => 7, // light gray
_ => termbox_simple::TB_DEFAULT as u8,
}
}

Expand Down
4 changes: 1 addition & 3 deletions crates/libtiny_tui/src/notifier.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
use crate::MsgTarget;

use libtiny_wire::formatting::remove_irc_control_chars;
use crate::{utils::remove_irc_control_chars, MsgTarget};

#[cfg(feature = "desktop-notifications")]
use notify_rust::Notification;
Expand Down
103 changes: 103 additions & 0 deletions crates/libtiny_tui/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,106 @@ pub(crate) fn is_nick_char(c: char) -> bool {
|| c == '-' // not valid according to RFC 2812 but servers accept it and I've seen nicks with
// this char in the wild
}

////////////////////////////////////////////////////////////////////////////////

use std::{iter::Peekable, str::Chars};

/// Parse at least one, at most two digits. Does not consume the iterator when
/// result is `None`.
fn parse_color_code(chars: &mut Peekable<Chars>) -> Option<u8> {
fn to_dec(ch: char) -> Option<u8> {
ch.to_digit(10).map(|c| c as u8)
}

let c1_char = *chars.peek()?;
let c1_digit = match to_dec(c1_char) {
None => {
return None;
}
Some(c1_digit) => {
chars.next();
c1_digit
}
};

match chars.peek().cloned() {
None => Some(c1_digit),
Some(c2) => match to_dec(c2) {
None => Some(c1_digit),
Some(c2_digit) => {
chars.next();
Some(c1_digit * 10 + c2_digit)
}
},
}
}

////////////////////////////////////////////////////////////////////////////////

/// Translate IRC color codes using the callback, replace tabs with 8 spaces, and remove other
/// ASCII control characters from the input.
pub(crate) fn translate_irc_control_chars(
str: &str,
push_color: fn(ret: &mut String, fg: u8, bg: Option<u8>),
) -> String {
let mut ret = String::with_capacity(str.len());
let mut iter = str.chars().peekable();

while let Some(char) = iter.next() {
if char == '\x03' {
match parse_color_code(&mut iter) {
None => {
// just skip the control char
}
Some(fg) => {
if let Some(char) = iter.peek().cloned() {
if char == ',' {
iter.next(); // consume ','
match parse_color_code(&mut iter) {
None => {
// comma was not part of the color code,
// add it to the new string
push_color(&mut ret, fg, None);
ret.push(char);
}
Some(bg) => {
push_color(&mut ret, fg, Some(bg));
}
}
} else {
push_color(&mut ret, fg, None);
}
} else {
push_color(&mut ret, fg, None);
}
}
}
} else if char == '\t' {
ret.push_str(" ");
} else if !char.is_ascii_control() {
ret.push(char);
}
}

ret
}

/// Like `translate_irc_control_chars`, but skips color codes.
pub(crate) fn remove_irc_control_chars(str: &str) -> String {
fn push_color(_ret: &mut String, _fg: u8, _bg: Option<u8>) {}
translate_irc_control_chars(str, push_color)
}

#[test]
fn test_translate_irc_control_chars() {
assert_eq!(
remove_irc_control_chars(" Le Voyageur imprudent "),
" Le Voyageur imprudent "
);
assert_eq!(remove_irc_control_chars("\x0301,02foo"), "foo");
assert_eq!(remove_irc_control_chars("\x0301,2foo"), "foo");
assert_eq!(remove_irc_control_chars("\x031,2foo"), "foo");
assert_eq!(remove_irc_control_chars("\x031,foo"), ",foo");
assert_eq!(remove_irc_control_chars("\x03,foo"), ",foo");
}
Loading

0 comments on commit 8f4d485

Please sign in to comment.