From 42ed55146e6a981264a5f147ab2dcb80014c037c Mon Sep 17 00:00:00 2001 From: phil Date: Thu, 9 Nov 2023 22:41:24 +0200 Subject: [PATCH] adds all the options in the worst possible way --- src/code_editor/editor.rs | 286 +++++++++++++++----------------------- src/helpers/languages.rs | 2 +- 2 files changed, 110 insertions(+), 178 deletions(-) diff --git a/src/code_editor/editor.rs b/src/code_editor/editor.rs index 426bdc8..9914a72 100644 --- a/src/code_editor/editor.rs +++ b/src/code_editor/editor.rs @@ -1,33 +1,29 @@ -use egui::{text_edit::CCursorRange, *}; +use crate::helpers::{submission::Submission, Challenges, Languages}; +use egui::*; #[derive(serde::Deserialize, serde::Serialize)] pub struct CodeEditor { code: String, - highlight_editor: bool, - show_rendered: bool, -} - -impl PartialEq for CodeEditor { - fn eq(&self, other: &Self) -> bool { - (&self.code, self.highlight_editor, self.show_rendered) - == (&other.code, other.highlight_editor, other.show_rendered) - } + show_instructions: bool, + run: Submission, + theme: egui_extras::syntax_highlighting::CodeTheme, } impl Default for CodeEditor { fn default() -> Self { Self { code: DEFAULT_CODE.trim().to_owned(), - highlight_editor: true, - show_rendered: true, + show_instructions: false, + run: Default::default(), + theme: egui_extras::syntax_highlighting::CodeTheme::default(), } } } impl CodeEditor { pub fn panels(&mut self, ctx: &egui::Context) { - egui::TopBottomPanel::bottom("easy_mark_bottom").show(ctx, |ui| { - let layout = egui::Layout::top_down(egui::Align::Center).with_main_justify(true); + egui::TopBottomPanel::bottom("easy_mark_bottom").show(ctx, |_ui| { + let _layout = egui::Layout::top_down(egui::Align::Center).with_main_justify(true); }); egui::CentralPanel::default().show(ctx, |ui| { @@ -38,21 +34,63 @@ impl CodeEditor { pub fn ui(&mut self, ui: &mut egui::Ui) { egui::Grid::new("controls").show(ui, |ui| { let _ = ui.button("Hotkeys").on_hover_ui(nested_hotkeys_ui); - ui.checkbox(&mut self.show_rendered, "Show rendered"); - ui.checkbox(&mut self.highlight_editor, "Highlight editor"); - egui::reset_button(ui, self); + ui.checkbox(&mut self.show_instructions, "Show Instructions"); + + if ui.button("Submit").clicked() { + log::debug!("Submitting code"); + todo!(); + } + if ui.button("Test").clicked() { + log::debug!("Testing code"); + todo!(); + } + egui::ComboBox::from_label("Challenge") + .selected_text(format!("{}", self.run.challenge)) + .show_ui(ui, |ui| { + ui.style_mut().wrap = Some(false); + ui.set_min_width(60.0); + + for challenge in Challenges::iter() { + ui.selectable_value( + &mut self.run.challenge, + challenge, + format!("{}", challenge), + ); + } + }); + ui.horizontal(|ui| { + ui.set_height(0.0); + + ui.label("Filename:"); + ui.add(egui::widgets::text_edit::TextEdit::singleline( + &mut self.run.filename, + )) + .on_hover_text("What would you like this to be called on the scoreboard?"); + }); + ui.horizontal(|ui| { + ui.label("Language:"); + + for l in Languages::iter() { + ui.selectable_value(&mut self.run.language, l, format!("{}", l)); + } + }); + ui.collapsing("Theme", |ui| { + ui.group(|ui| { + self.theme.ui(ui); + }); + }); ui.end_row(); }); ui.separator(); - if self.show_rendered { + if self.show_instructions { ui.columns(2, |columns| { ScrollArea::vertical() .id_source("source") .show(&mut columns[0], |ui| self.editor_ui(ui)); ScrollArea::vertical() .id_source("rendered") - .show(&mut columns[1], |ui| {}); + .show(&mut columns[1], |_ui| {}); }); } else { ScrollArea::vertical() @@ -61,21 +99,32 @@ impl CodeEditor { } } - fn editor_ui(&mut self, ui: &mut egui::Ui) {} + fn editor_ui(&mut self, ui: &mut egui::Ui) { + let mut layouter = |ui: &egui::Ui, string: &str, wrap_width: f32| { + let mut layout_job = egui_extras::syntax_highlighting::highlight( + ui.ctx(), + &self.theme, + string, + &self.run.language.to_string(), + ); + layout_job.wrap.max_width = wrap_width; + ui.fonts(|f| f.layout_job(layout_job)) + }; + + ui.add( + egui::TextEdit::multiline(&mut self.code) + .font(egui::TextStyle::Monospace) // for cursor height + .code_editor() + .desired_rows(10) + .lock_focus(true) + .desired_width(f32::INFINITY) + .layouter(&mut layouter), + ); + } } -pub const SHORTCUT_BOLD: KeyboardShortcut = KeyboardShortcut::new(Modifiers::COMMAND, Key::B); -pub const SHORTCUT_CODE: KeyboardShortcut = KeyboardShortcut::new(Modifiers::COMMAND, Key::N); -pub const SHORTCUT_ITALICS: KeyboardShortcut = KeyboardShortcut::new(Modifiers::COMMAND, Key::I); -pub const SHORTCUT_SUBSCRIPT: KeyboardShortcut = KeyboardShortcut::new(Modifiers::COMMAND, Key::L); -pub const SHORTCUT_SUPERSCRIPT: KeyboardShortcut = - KeyboardShortcut::new(Modifiers::COMMAND, Key::Y); -pub const SHORTCUT_STRIKETHROUGH: KeyboardShortcut = - KeyboardShortcut::new(Modifiers::CTRL.plus(Modifiers::SHIFT), Key::Q); -pub const SHORTCUT_UNDERLINE: KeyboardShortcut = - KeyboardShortcut::new(Modifiers::CTRL.plus(Modifiers::SHIFT), Key::W); -pub const SHORTCUT_INDENT: KeyboardShortcut = - KeyboardShortcut::new(Modifiers::CTRL.plus(Modifiers::SHIFT), Key::E); +pub const SHORTCUT_TEST: KeyboardShortcut = KeyboardShortcut::new(Modifiers::COMMAND, Key::T); +pub const SHORTCUT_SUBMIT: KeyboardShortcut = KeyboardShortcut::new(Modifiers::COMMAND, Key::R); fn nested_hotkeys_ui(ui: &mut egui::Ui) { egui::Grid::new("shortcuts").striped(true).show(ui, |ui| { @@ -85,155 +134,38 @@ fn nested_hotkeys_ui(ui: &mut egui::Ui) { ui.end_row(); }; - label(SHORTCUT_BOLD, "*bold*"); - label(SHORTCUT_CODE, "`code`"); - label(SHORTCUT_ITALICS, "/italics/"); - label(SHORTCUT_SUBSCRIPT, "$subscript$"); - label(SHORTCUT_SUPERSCRIPT, "^superscript^"); - label(SHORTCUT_STRIKETHROUGH, "~strikethrough~"); - label(SHORTCUT_UNDERLINE, "_underline_"); - label(SHORTCUT_INDENT, "two spaces"); // Placeholder for tab indent + label(SHORTCUT_TEST, "Test"); + label(SHORTCUT_SUBMIT, "Submit"); }); } -fn shortcuts(ui: &Ui, code: &mut dyn TextBuffer, ccursor_range: &mut CCursorRange) -> bool { - let mut any_change = false; - - if ui.input_mut(|i| i.consume_shortcut(&SHORTCUT_INDENT)) { - // This is a placeholder till we can indent the active line - any_change = true; - let [primary, _secondary] = ccursor_range.sorted(); - - let advance = code.insert_text(" ", primary.index); - ccursor_range.primary.index += advance; - ccursor_range.secondary.index += advance; - } - - for (shortcut, surrounding) in [ - (SHORTCUT_BOLD, "*"), - (SHORTCUT_CODE, "`"), - (SHORTCUT_ITALICS, "/"), - (SHORTCUT_SUBSCRIPT, "$"), - (SHORTCUT_SUPERSCRIPT, "^"), - (SHORTCUT_STRIKETHROUGH, "~"), - (SHORTCUT_UNDERLINE, "_"), - ] { - if ui.input_mut(|i| i.consume_shortcut(&shortcut)) { - any_change = true; - toggle_surrounding(code, ccursor_range, surrounding); - }; - } - - any_change -} - -/// E.g. toggle *strong* with `toggle_surrounding(&mut text, &mut cursor, "*")` -fn toggle_surrounding( - code: &mut dyn TextBuffer, - ccursor_range: &mut CCursorRange, - surrounding: &str, -) { - let [primary, secondary] = ccursor_range.sorted(); - - let surrounding_ccount = surrounding.chars().count(); - - let prefix_crange = primary.index.saturating_sub(surrounding_ccount)..primary.index; - let suffix_crange = secondary.index..secondary.index.saturating_add(surrounding_ccount); - let already_surrounded = code.char_range(prefix_crange.clone()) == surrounding - && code.char_range(suffix_crange.clone()) == surrounding; - - if already_surrounded { - code.delete_char_range(suffix_crange); - code.delete_char_range(prefix_crange); - ccursor_range.primary.index -= surrounding_ccount; - ccursor_range.secondary.index -= surrounding_ccount; - } else { - code.insert_text(surrounding, secondary.index); - let advance = code.insert_text(surrounding, primary.index); - - ccursor_range.primary.index += advance; - ccursor_range.secondary.index += advance; - } -} - // ---------------------------------------------------------------------------- const DEFAULT_CODE: &str = r#" -# EasyMark -EasyMark is a markup language, designed for extreme simplicity. - -``` -WARNING: EasyMark is still an evolving specification, -and is also missing some features. -``` - ----------------- - -# At a glance -- inline text: - - normal, `code`, *strong*, ~strikethrough~, _underline_, /italics/, ^raised^, $small$ - - `\` escapes the next character - - [hyperlink](https://github.com/emilk/egui) - - Embedded URL: -- `# ` header -- `---` separator (horizontal line) -- `> ` quote -- `- ` bullet list -- `1. ` numbered list -- \`\`\` code fence -- a^2^ + b^2^ = c^2^ -- $Remember to read the small print$ - -# Design -> /"Why do what everyone else is doing, when everyone else is already doing it?" -> \- Emil - -Goals: -1. easy to parse -2. easy to learn -3. similar to markdown - -[The reference parser](https://github.com/emilk/egui/blob/master/crates/egui_demo_lib/src/easy_mark/easy_mark_parser.rs) is \~250 lines of code, using only the Rust standard library. The parser uses no look-ahead or recursion. - -There is never more than one way to accomplish the same thing, and each special character is only used for one thing. For instance `*` is used for *strong* and `-` is used for bullet lists. There is no alternative way to specify the *strong* style or getting a bullet list. - -Similarity to markdown is kept when possible, but with much less ambiguity and some improvements (like _underlining_). - -# Details -All style changes are single characters, so it is `*strong*`, NOT `**strong**`. Style is reset by a matching character, or at the end of the line. - -Style change characters and escapes (`\`) work everywhere except for in inline code, code blocks and in URLs. - -You can mix styles. For instance: /italics _underline_/ and *strong `code`*. - -You can use styles on URLs: ~my webpage is at ~. - -Newlines are preserved. If you want to continue text on the same line, just do so. Alternatively, escape the newline by ending the line with a backslash (`\`). \ -Escaping the newline effectively ignores it. - -The style characters are chosen to be similar to what they are representing: - `_` = _underline_ - `~` = ~strikethrough~ (`-` is used for bullet points) - `/` = /italics/ - `*` = *strong* - `$` = $small$ - `^` = ^raised^ - -# TODO -- Sub-headers (`## h2`, `### h3` etc) -- Hotkey Editor -- International keyboard algorithm for non-letter keys -- ALT+SHIFT+Num1 is not a functioning hotkey -- Tab Indent Increment/Decrement CTRL+], CTRL+[ - -- Images - - we want to be able to optionally specify size (width and\/or height) - - centering of images is very desirable - - captioning (image with a text underneath it) - - `![caption=My image][width=200][center](url)` ? -- Nicer URL:s - - `` and `[url](url)` do the same thing yet look completely different. - - let's keep similarity with images -- Tables -- Inspiration: +import json +import sys + +def main(): + for line in sys.stdin: + if line == "q\n": break + if line == "\n": + sys.stdout.write("0") + sys.stdout.write("\n") + sys.stdout.flush() + continue + input_ints = line.rstrip().split(',') + answer = find_the_number(input_ints) + sys.stdout.write(answer) + sys.stdout.write("\n") + sys.stdout.flush() + +def find_the_number(int_list): + unique_ints = set(int_list) + for integer in unique_ints: + if int_list.count(integer) % 2 != 0: + # print("the number that appears an odd number of times is", integer) + return integer + + +main() "#; diff --git a/src/helpers/languages.rs b/src/helpers/languages.rs index 5857dce..fafd462 100644 --- a/src/helpers/languages.rs +++ b/src/helpers/languages.rs @@ -4,13 +4,13 @@ use std::fmt::{self, Display, Formatter}; Debug, Default, PartialEq, Eq, Hash, Copy, Clone, serde::Deserialize, serde::Serialize, )] pub enum Languages { - #[default] C, Cpp, CSharp, Go, Java, JavaScript, + #[default] Python, Rust, ShellScript,