- updated to-dos
- removed unnecessary debugging code - moved x86_64-kernel.json to the project root
This commit is contained in:
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
[build]
|
[build]
|
||||||
target = "x86_64-kernel"
|
target = "x86_64-kernel.json"
|
||||||
target-dir = "build/target"
|
target-dir = "build/target"
|
||||||
|
|
||||||
[unstable]
|
[unstable]
|
||||||
|
|||||||
Generated
+2
@@ -4,6 +4,8 @@
|
|||||||
<content url="file://$MODULE_DIR$">
|
<content url="file://$MODULE_DIR$">
|
||||||
<sourceFolder url="file://$MODULE_DIR$/kernel/src" isTestSource="false" />
|
<sourceFolder url="file://$MODULE_DIR$/kernel/src" isTestSource="false" />
|
||||||
<sourceFolder url="file://$MODULE_DIR$/lib_example/src" isTestSource="false" />
|
<sourceFolder url="file://$MODULE_DIR$/lib_example/src" isTestSource="false" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/libk/src" isTestSource="false" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/libm/src" isTestSource="false" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/target" />
|
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||||
</content>
|
</content>
|
||||||
<orderEntry type="inheritedJdk" />
|
<orderEntry type="inheritedJdk" />
|
||||||
|
|||||||
Vendored
+3
-1
@@ -1 +1,3 @@
|
|||||||
{}
|
{
|
||||||
|
"cssTheme": "Dark Moss"
|
||||||
|
}
|
||||||
Vendored
+9
-29
@@ -3,26 +3,6 @@
|
|||||||
"id": "20da7b1c0adc4114",
|
"id": "20da7b1c0adc4114",
|
||||||
"type": "split",
|
"type": "split",
|
||||||
"children": [
|
"children": [
|
||||||
{
|
|
||||||
"id": "6bf1f87bf81a3031",
|
|
||||||
"type": "tabs",
|
|
||||||
"children": [
|
|
||||||
{
|
|
||||||
"id": "add883d295e04659",
|
|
||||||
"type": "leaf",
|
|
||||||
"state": {
|
|
||||||
"type": "markdown",
|
|
||||||
"state": {
|
|
||||||
"file": "Planning & To-Dos.md",
|
|
||||||
"mode": "source",
|
|
||||||
"source": false
|
|
||||||
},
|
|
||||||
"icon": "lucide-file",
|
|
||||||
"title": "Planning & To-Dos"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"id": "c178a2dff57ae0aa",
|
"id": "c178a2dff57ae0aa",
|
||||||
"type": "tabs",
|
"type": "tabs",
|
||||||
@@ -34,7 +14,7 @@
|
|||||||
"type": "markdown",
|
"type": "markdown",
|
||||||
"state": {
|
"state": {
|
||||||
"file": "Planning & To-Dos.md",
|
"file": "Planning & To-Dos.md",
|
||||||
"mode": "preview",
|
"mode": "source",
|
||||||
"source": false
|
"source": false
|
||||||
},
|
},
|
||||||
"icon": "lucide-file",
|
"icon": "lucide-file",
|
||||||
@@ -73,7 +53,7 @@
|
|||||||
"state": {
|
"state": {
|
||||||
"type": "search",
|
"type": "search",
|
||||||
"state": {
|
"state": {
|
||||||
"query": "tag:#Threading",
|
"query": "",
|
||||||
"matchingCase": false,
|
"matchingCase": false,
|
||||||
"explainSearch": false,
|
"explainSearch": false,
|
||||||
"collapseAll": false,
|
"collapseAll": false,
|
||||||
@@ -94,12 +74,11 @@
|
|||||||
"title": "Bookmarks"
|
"title": "Bookmarks"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
]
|
||||||
"currentTab": 1
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"direction": "horizontal",
|
"direction": "horizontal",
|
||||||
"width": 200
|
"width": 307.5
|
||||||
},
|
},
|
||||||
"right": {
|
"right": {
|
||||||
"id": "baa2a8e61b737fa6",
|
"id": "baa2a8e61b737fa6",
|
||||||
@@ -177,7 +156,8 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"direction": "horizontal",
|
"direction": "horizontal",
|
||||||
"width": 300
|
"width": 300,
|
||||||
|
"collapsed": true
|
||||||
},
|
},
|
||||||
"left-ribbon": {
|
"left-ribbon": {
|
||||||
"hiddenItems": {
|
"hiddenItems": {
|
||||||
@@ -185,11 +165,11 @@
|
|||||||
"graph:Open graph view": false,
|
"graph:Open graph view": false,
|
||||||
"canvas:Create new canvas": false,
|
"canvas:Create new canvas": false,
|
||||||
"daily-notes:Open today's daily note": false,
|
"daily-notes:Open today's daily note": false,
|
||||||
"templates:Insert template": false,
|
"command-palette:Open command palette": false,
|
||||||
"command-palette:Open command palette": false
|
"templates:Insert template": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"active": "add883d295e04659",
|
"active": "6d395e6a4c72e1c8",
|
||||||
"lastOpenFiles": [
|
"lastOpenFiles": [
|
||||||
"Usage/Building The Kernel.md",
|
"Usage/Building The Kernel.md",
|
||||||
"Planning & To-Dos.md",
|
"Planning & To-Dos.md",
|
||||||
|
|||||||
@@ -1,3 +1,24 @@
|
|||||||
|
> [!todo] Testing
|
||||||
|
> - [ ] setup custom test frameworks (Use CrystalOS-V2 as a reference)
|
||||||
|
> - [ ] write a sub-crate for tests
|
||||||
|
> - [ ] implement several unit tests on things that we are likely to break often
|
||||||
|
> - [ ] setup Git CI/CD pipeline with testing
|
||||||
|
> - [ ] figure out how to run QEMU in the test environment
|
||||||
|
> - [ ] write a script to run tests
|
||||||
|
> - [ ] a release should only be published if all tests pass
|
||||||
|
|
||||||
|
> [!todo] Allocator
|
||||||
|
> - [ ] learn about several allocator designs and decide on the optimal one
|
||||||
|
> - [ ] implementation
|
||||||
|
> - [ ] implement an allocate method
|
||||||
|
> - [ ] implement a deallocate method
|
||||||
|
> - [ ] set the global allocator
|
||||||
|
> - [ ] testing
|
||||||
|
> - [ ] write unit tests
|
||||||
|
> - [ ] many allocations
|
||||||
|
> - [ ] large allocations
|
||||||
|
> - [ ] allocating more memory than is available
|
||||||
|
> - [ ] pass unit tests
|
||||||
|
|
||||||
> [!todo] Threading
|
> [!todo] Threading
|
||||||
> - [ ] implement thread switching functionality
|
> - [ ] implement thread switching functionality
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ use x86_64::structures::paging::{FrameAllocator, Mapper, Page, PageTableFlags, S
|
|||||||
|
|
||||||
use spin::{Lazy, Mutex};
|
use spin::{Lazy, Mutex};
|
||||||
|
|
||||||
use super::apic::enable_apic;
|
|
||||||
use super::gdt;
|
use super::gdt;
|
||||||
|
|
||||||
static IDT: Lazy<InterruptDescriptorTable> = Lazy::new(|| {
|
static IDT: Lazy<InterruptDescriptorTable> = Lazy::new(|| {
|
||||||
@@ -92,7 +91,7 @@ extern "x86-interrupt" fn double_fault_handler(
|
|||||||
}
|
}
|
||||||
|
|
||||||
extern "x86-interrupt" fn keyboard_interrupt_handler(_stack_frame: InterruptStackFrame) {
|
extern "x86-interrupt" fn keyboard_interrupt_handler(_stack_frame: InterruptStackFrame) {
|
||||||
use pc_keyboard::{HandleControl, Keyboard, ScancodeSet1, layouts};
|
use pc_keyboard::{layouts, HandleControl, Keyboard, ScancodeSet1};
|
||||||
// use pc_keyboard::DecodedKey;
|
// use pc_keyboard::DecodedKey;
|
||||||
use spin::Mutex;
|
use spin::Mutex;
|
||||||
use x86_64::instructions::port::Port;
|
use x86_64::instructions::port::Port;
|
||||||
@@ -125,13 +124,13 @@ extern "x86-interrupt" fn timer_interrupt_handler(_stack_frame: InterruptStackFr
|
|||||||
}
|
}
|
||||||
|
|
||||||
extern "x86-interrupt" fn page_fault_handler(
|
extern "x86-interrupt" fn page_fault_handler(
|
||||||
stack_frame: InterruptStackFrame,
|
_stack_frame: InterruptStackFrame,
|
||||||
error_code: PageFaultErrorCode,
|
_error_code: PageFaultErrorCode,
|
||||||
) {
|
) {
|
||||||
// serial_println!("Exception: Page Fault");
|
// serial_println!("Exception: Page Fault");
|
||||||
// serial_println!("Accessed Address: {:?}", Cr2::read());
|
// serial_println!("Accessed Address: {:?}", Cr2::read());
|
||||||
// serial_println!("Error Code: {:?}", error_code);
|
// serial_println!("Error Code: {:?}", error_code);
|
||||||
// serial_println!("{:#?}", stack_frame);
|
// serial_println!("{:#?}", _stack_frame);
|
||||||
|
|
||||||
if let Some(frame_allocator) = FRAME_ALLOCATOR.get() {
|
if let Some(frame_allocator) = FRAME_ALLOCATOR.get() {
|
||||||
let mut f = frame_allocator.lock();
|
let mut f = frame_allocator.lock();
|
||||||
|
|||||||
+1
-1
@@ -79,7 +79,7 @@ pub fn boot() -> Result<(), &'static str> {
|
|||||||
|
|
||||||
print_log!(" Initialising Memory Subsystem... ");
|
print_log!(" Initialising Memory Subsystem... ");
|
||||||
let physical_memory_offset = VirtAddr::new(*memmap::PHYSICAL_MEMORY_OFFSET);
|
let physical_memory_offset = VirtAddr::new(*memmap::PHYSICAL_MEMORY_OFFSET);
|
||||||
let mut l4_table = memory::init_page_table(physical_memory_offset);
|
memory::init_page_table(physical_memory_offset);
|
||||||
println_log!("[Success]");
|
println_log!("[Success]");
|
||||||
|
|
||||||
print_log!(" Setting Up Page Table... ");
|
print_log!(" Setting Up Page Table... ");
|
||||||
|
|||||||
+2
-16
@@ -28,23 +28,9 @@ extern "C" fn kmain() -> ! {
|
|||||||
println!("Dimensions: {}x{} (px)", dimensions2.0, dimensions2.1);
|
println!("Dimensions: {}x{} (px)", dimensions2.0, dimensions2.1);
|
||||||
println!("Dimensions: {}x{} (chars)", dimensions.0, dimensions.1);
|
println!("Dimensions: {}x{} (chars)", dimensions.0, dimensions.1);
|
||||||
|
|
||||||
let vector = vec![0; 100];
|
|
||||||
println!("vec 100 works");
|
|
||||||
let vector2 = vec![0; 1000];
|
|
||||||
println!("vec 1000 works");
|
|
||||||
let vector3 = vec![0; 10000];
|
|
||||||
println!("vec 10000 works");
|
|
||||||
let vector4 = vec![vec![Colour::Black; 1000]; 1000];
|
|
||||||
println!("vec 100000 works");
|
|
||||||
|
|
||||||
let mut executor = Executor::new();
|
let mut executor = Executor::new();
|
||||||
|
|
||||||
let mut v = Vec::with_capacity(1000 * 1000);
|
|
||||||
for i in 0..1000 * 1000 {
|
|
||||||
v.push(i);
|
|
||||||
}
|
|
||||||
println!("v.len(): {}", v.len());
|
|
||||||
|
|
||||||
executor.spawn(Task::new(shell()));
|
executor.spawn(Task::new(shell()));
|
||||||
executor.run();
|
executor.run();
|
||||||
|
|
||||||
|
loop {}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -18,5 +18,5 @@ spin = "0.9.8"
|
|||||||
futures-util = { version = "0.3.31", default-features = false, features = [
|
futures-util = { version = "0.3.31", default-features = false, features = [
|
||||||
"alloc",
|
"alloc",
|
||||||
] }
|
] }
|
||||||
linked_list_allocator = "0.10.5"
|
linked_list_allocator = { version = "0.10.5", features = ["use_spin"] }
|
||||||
libm = { path = "../libm" }
|
libm = { path = "../libm" }
|
||||||
|
|||||||
@@ -1,15 +1,7 @@
|
|||||||
use linked_list_allocator::LockedHeap;
|
use linked_list_allocator::LockedHeap;
|
||||||
use x86_64::{
|
use x86_64::structures::paging::{
|
||||||
VirtAddr,
|
mapper::MapToError,
|
||||||
structures::paging::{
|
Size4KiB,
|
||||||
FrameAllocator, Mapper, Page, PageTableFlags, Size4KiB,
|
|
||||||
mapper::{MapToError, MapperFlushAll},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
drivers::memory::{FRAME_ALLOCATOR, OFFSET_PAGE_TABLE},
|
|
||||||
serial_print, serial_println,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// We are currently using a linked list heap allocator which uses our underlying page allocator.
|
/// We are currently using a linked list heap allocator which uses our underlying page allocator.
|
||||||
@@ -24,46 +16,7 @@ pub const HEAP_SIZE: usize = 1024 * 1024 * 1024;
|
|||||||
|
|
||||||
/// Sets up the heap using the backing page frame allocator.
|
/// Sets up the heap using the backing page frame allocator.
|
||||||
pub fn init_heap() -> Result<(), MapToError<Size4KiB>> {
|
pub fn init_heap() -> Result<(), MapToError<Size4KiB>> {
|
||||||
// let mut frame_allocator = if let Some(f) = FRAME_ALLOCATOR.get() {
|
// code to allocate frames is now done in the page fault interrupt handler!
|
||||||
// f.lock()
|
|
||||||
// } else {
|
|
||||||
// return Err(MapToError::FrameAllocationFailed);
|
|
||||||
// };
|
|
||||||
|
|
||||||
// let mut mapper = if let Some(m) = OFFSET_PAGE_TABLE.get() {
|
|
||||||
// m.lock()
|
|
||||||
// } else {
|
|
||||||
// return Err(MapToError::FrameAllocationFailed);
|
|
||||||
// };
|
|
||||||
|
|
||||||
// let range = {
|
|
||||||
// let heap_start = VirtAddr::new(HEAP_START as u64);
|
|
||||||
// let heap_end = heap_start + HEAP_SIZE as u64 - 1u64;
|
|
||||||
// let heap_start_page = Page::<Size4KiB>::containing_address(heap_start);
|
|
||||||
// let heap_end_page = Page::<Size4KiB>::containing_address(heap_end);
|
|
||||||
// Page::range_inclusive(heap_start_page, heap_end_page)
|
|
||||||
// };
|
|
||||||
|
|
||||||
// let usable_frames = frame_allocator.count_usable_frames();
|
|
||||||
// serial_println!("usable frames: {}", usable_frames);
|
|
||||||
|
|
||||||
// let mut i = 0;
|
|
||||||
// for page in range {
|
|
||||||
// i += 1;
|
|
||||||
// if i % 128 == 0 {
|
|
||||||
// serial_println!("allocated {} pages", i);
|
|
||||||
// }
|
|
||||||
// let frame = frame_allocator
|
|
||||||
// .allocate_frame()
|
|
||||||
// .ok_or(MapToError::FrameAllocationFailed)?;
|
|
||||||
// let flags = PageTableFlags::PRESENT | PageTableFlags::WRITABLE;
|
|
||||||
// unsafe {
|
|
||||||
// // IMPORTANT: make sure to flush the mapper!!!!
|
|
||||||
// let _ = mapper.map_to(page, frame, flags, &mut *frame_allocator)?;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// MapperFlushAll::new().flush_all();
|
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
ALLOCATOR.lock().init(HEAP_START as *mut u8, HEAP_SIZE);
|
ALLOCATOR.lock().init(HEAP_START as *mut u8, HEAP_SIZE);
|
||||||
|
|||||||
@@ -2,12 +2,12 @@
|
|||||||
use limine::{memory_map::EntryType, response::MemoryMapResponse};
|
use limine::{memory_map::EntryType, response::MemoryMapResponse};
|
||||||
use spin::{Mutex, Once};
|
use spin::{Mutex, Once};
|
||||||
use x86_64::{
|
use x86_64::{
|
||||||
PhysAddr, VirtAddr,
|
registers::control::Cr3, structures::paging::{
|
||||||
registers::control::Cr3,
|
FrameAllocator, OffsetPageTable, PageTable, PhysFrame, Size4KiB
|
||||||
structures::paging::{
|
,
|
||||||
FrameAllocator, Mapper, OffsetPageTable, Page, PageTable, PhysFrame, Size4KiB,
|
|
||||||
page_table::FrameError,
|
|
||||||
},
|
},
|
||||||
|
PhysAddr,
|
||||||
|
VirtAddr,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub static FRAME_ALLOCATOR: Once<Mutex<FoundryOSFrameAllocator>> = Once::new();
|
pub static FRAME_ALLOCATOR: Once<Mutex<FoundryOSFrameAllocator>> = Once::new();
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
use alloc::vec::Vec;
|
|
||||||
|
|
||||||
use crate::{drivers::io::framebuffer::colour::Colour, resources::font::Font};
|
use crate::{drivers::io::framebuffer::colour::Colour, resources::font::Font};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
|
|||||||
+76
-15
@@ -44,53 +44,110 @@ impl<'a> Editor {
|
|||||||
|
|
||||||
let (width, height) = writer.font_size().into();
|
let (width, height) = writer.font_size().into();
|
||||||
|
|
||||||
let mut col = Self::PADDING;
|
let mut col = 0;
|
||||||
let mut line = Self::PADDING;
|
let mut line = 0;
|
||||||
let mut scale = 1;
|
let mut scale = 1;
|
||||||
|
|
||||||
for ch in self.buffer.chars() {
|
for ch in self.buffer.chars() {
|
||||||
if ch == '\n' {
|
if ch == '\n' {
|
||||||
line += scale * height;
|
line += scale;
|
||||||
col = Self::PADDING;
|
col = 0;
|
||||||
scale = 1;
|
scale = 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if width * scale + col > frame.dimensions().x() {
|
if width * (col + 1) > frame.dimensions().x() - 2 * Self::PADDING {
|
||||||
line += scale * height;
|
line += scale;
|
||||||
col = Self::PADDING;
|
col = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
writer.render_glyph(&mut frame, Vec2::new(col, line), ch as u8, scale)?;
|
writer.render_glyph(
|
||||||
col += scale * width;
|
&mut frame,
|
||||||
|
Vec2::new(col * width + Self::PADDING, line * height + Self::PADDING),
|
||||||
|
ch as u8,
|
||||||
|
scale,
|
||||||
|
)?;
|
||||||
|
col += scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
writer.render_glyph(
|
||||||
|
&mut frame,
|
||||||
|
Vec2::new(
|
||||||
|
self.cursor_col * width + Self::PADDING,
|
||||||
|
self.cursor_line * height + Self::PADDING,
|
||||||
|
),
|
||||||
|
b'_',
|
||||||
|
scale,
|
||||||
|
);
|
||||||
|
|
||||||
Ok(frame)
|
Ok(frame)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(unused_variables, dead_code, clippy::needless_pass_by_ref_mut)]
|
||||||
fn get_lines(&self) -> Vec<&str> {
|
fn get_lines(&self) -> Vec<&str> {
|
||||||
self.buffer.split('\n').collect::<Vec<&str>>();
|
self.buffer.split('\n').collect::<Vec<&str>>()
|
||||||
todo!()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused_variables, dead_code, clippy::needless_pass_by_ref_mut)]
|
#[allow(unused_variables, dead_code, clippy::needless_pass_by_ref_mut)]
|
||||||
fn move_cursor(&mut self, x: i32, y: i32) {
|
fn move_cursor(&mut self, x: i32, y: i32) {
|
||||||
todo!()
|
self.cursor_line = self
|
||||||
|
.cursor_line
|
||||||
|
.checked_add_signed(y as isize)
|
||||||
|
.unwrap_or(self.cursor_line);
|
||||||
|
self.cursor_col = self
|
||||||
|
.cursor_col
|
||||||
|
.checked_add_signed(x as isize)
|
||||||
|
.unwrap_or(self.cursor_col);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused_variables, dead_code, clippy::needless_pass_by_ref_mut)]
|
#[allow(unused_variables, dead_code, clippy::needless_pass_by_ref_mut)]
|
||||||
fn delete_char(&mut self) {
|
fn delete_char(&mut self) {
|
||||||
todo!()
|
let i = self.get_char_idx();
|
||||||
|
self.buffer.remove(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused_variables, dead_code, clippy::needless_pass_by_ref_mut)]
|
#[allow(unused_variables, dead_code, clippy::needless_pass_by_ref_mut)]
|
||||||
fn insert_char(&mut self, c: char) {
|
fn insert_char(&mut self, c: char) {
|
||||||
todo!()
|
let i = self.get_char_idx();
|
||||||
|
self.buffer.insert(i, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused_variables, dead_code, clippy::needless_pass_by_ref_mut)]
|
#[allow(unused_variables, dead_code, clippy::needless_pass_by_ref_mut)]
|
||||||
fn splitline(&mut self) {
|
fn splitline(&mut self) {
|
||||||
todo!()
|
let i = self.get_char_idx();
|
||||||
|
self.buffer.insert(i, '\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_char_idx(&self) -> usize {
|
||||||
|
let frame = Frame::new(&self.window);
|
||||||
|
let writer = Writer::new(Font::default());
|
||||||
|
let (width, _height) = writer.font_size().into();
|
||||||
|
|
||||||
|
let mut col = 0;
|
||||||
|
let mut line = 0;
|
||||||
|
let mut scale = 1;
|
||||||
|
|
||||||
|
for (i, ch) in self.buffer.chars().enumerate() {
|
||||||
|
if ch == '\n' {
|
||||||
|
line += scale;
|
||||||
|
col = 0;
|
||||||
|
scale = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if width * (col + 1) > frame.dimensions().x() - 2 * Self::PADDING {
|
||||||
|
line += scale;
|
||||||
|
col = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if col == self.cursor_col && line == self.cursor_line {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
col += scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -139,15 +196,19 @@ impl Application for Editor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
KeyStroke::Left => {
|
KeyStroke::Left => {
|
||||||
|
serial_println!("Left\n");
|
||||||
self.move_cursor(-1, 0);
|
self.move_cursor(-1, 0);
|
||||||
}
|
}
|
||||||
KeyStroke::Right => {
|
KeyStroke::Right => {
|
||||||
|
serial_println!("Right\n");
|
||||||
self.move_cursor(1, 0);
|
self.move_cursor(1, 0);
|
||||||
}
|
}
|
||||||
KeyStroke::Up => {
|
KeyStroke::Up => {
|
||||||
|
serial_println!("Up\n");
|
||||||
self.move_cursor(0, -1);
|
self.move_cursor(0, -1);
|
||||||
}
|
}
|
||||||
KeyStroke::Down => {
|
KeyStroke::Down => {
|
||||||
|
serial_println!("Down\n");
|
||||||
self.move_cursor(0, 1);
|
self.move_cursor(0, 1);
|
||||||
}
|
}
|
||||||
KeyStroke::None => {}
|
KeyStroke::None => {}
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
[toolchain]
|
||||||
|
channel = "nightly"
|
||||||
|
targets = ["x86_64-linux-gnu"]
|
||||||
Reference in New Issue
Block a user