Add Rust filetype, full tests for Option
Some checks failed
timw4mail/scroll/pipeline/head There was a failure building this commit
Some checks failed
timw4mail/scroll/pipeline/head There was a failure building this commit
This commit is contained in:
parent
a7fcc982fe
commit
d59900a895
@ -4,6 +4,3 @@ deno test --allow-all --coverage=coverage
|
||||
deno coverage coverage --lcov > coverage/coverage.lcov
|
||||
genhtml -o coverage coverage/coverage.lcov
|
||||
rm coverage/*.json
|
||||
open coverage/index.html
|
||||
|
||||
|
||||
|
1686
demo/editor.rs
Normal file
1686
demo/editor.rs
Normal file
File diff suppressed because it is too large
Load Diff
8
justfile
8
justfile
@ -5,6 +5,10 @@ default:
|
||||
# Test coverage
|
||||
coverage: deno-coverage bun-coverage
|
||||
|
||||
# Generate test coverage and open report in default browser
|
||||
open-coverage: coverage
|
||||
open coverage/index.html
|
||||
|
||||
# Typescript checking
|
||||
check: deno-check bun-check
|
||||
|
||||
@ -12,6 +16,10 @@ check: deno-check bun-check
|
||||
docs:
|
||||
deno doc --html --name="Scroll" ./src/scroll.ts ./src/common/*.ts ./src/deno/mod.ts ./src/bun/mod.ts ./src/tsx/mod.ts
|
||||
|
||||
# Generate source docs and open in default browser
|
||||
open-docs: docs
|
||||
open docs/all_symbols.html
|
||||
|
||||
# Reformat the code
|
||||
fmt:
|
||||
deno fmt
|
||||
|
@ -500,11 +500,78 @@ const OptionTest = {
|
||||
assertEquivalent(Option.from(Some('foo')), Some('foo'));
|
||||
assertEquivalent(Some(Some('bar')), Some('bar'));
|
||||
},
|
||||
'.isSome': () => {
|
||||
assertFalse(None.isSome());
|
||||
assertTrue(Option.from('foo').isSome());
|
||||
assertTrue(Some('foo').isSome());
|
||||
},
|
||||
'.isNone': () => {
|
||||
assertTrue(None.isNone());
|
||||
assertFalse(Option.from('foo').isNone());
|
||||
assertFalse(Some('foo').isNone());
|
||||
},
|
||||
'.toString': () => {
|
||||
assertEquals(Some({}).toString(), 'Some ({})');
|
||||
assertEquals(Some([1, 2, 3]).toString(), 'Some ([1,2,3])');
|
||||
assertEquals(None.toString(), 'None');
|
||||
},
|
||||
'.isSomeAnd': () => {
|
||||
assertFalse(Option.from().isSomeAnd((_a) => true));
|
||||
assertTrue(Option.from('foo').isSomeAnd((a) => typeof a === 'string'));
|
||||
},
|
||||
'.isNoneAnd': () => {
|
||||
assertTrue(None.isNoneAnd(() => true));
|
||||
assertFalse(None.isNoneAnd(() => false));
|
||||
assertFalse(Some('x').isNoneAnd(() => true));
|
||||
},
|
||||
'.map': () => {
|
||||
const fn = (_a: any) => 'bar';
|
||||
|
||||
assertEquivalent(Some('bar'), Some('foo').map(fn));
|
||||
assertNone(None.map(fn));
|
||||
},
|
||||
'.mapOr': () => {
|
||||
const fn = (_a: any) => 'bar';
|
||||
|
||||
assertEquals('bar', Some('foo').mapOr('baz', fn));
|
||||
assertEquals('baz', None.mapOr('baz', fn));
|
||||
},
|
||||
'.mapOrElse': () => {
|
||||
const fn = (_a: any) => 'bar';
|
||||
const defFn = () => 'baz';
|
||||
|
||||
assertEquals('bar', Some('foo').mapOrElse(defFn, fn));
|
||||
assertEquals('baz', None.mapOrElse(defFn, fn));
|
||||
},
|
||||
'.unwrapOr': () => {
|
||||
assertEquals('foo', Some('foo').unwrapOr('bar'));
|
||||
assertEquals('bar', None.unwrapOr('bar'));
|
||||
},
|
||||
'.unwrapOrElse': () => {
|
||||
const fn = () => 'bar';
|
||||
assertEquals('foo', Some('foo').unwrapOrElse(fn));
|
||||
assertEquals('bar', None.unwrapOrElse(fn));
|
||||
},
|
||||
'.and': () => {
|
||||
const optb = Some('bar');
|
||||
assertEquivalent(optb, Some('foo').and(optb));
|
||||
assertEquivalent(None, None.and(optb));
|
||||
},
|
||||
'.andThen': () => {
|
||||
const fn = (x: any) => Some(typeof x === 'string');
|
||||
assertEquivalent(Some(true), Some('foo').andThen(fn));
|
||||
assertNone(None.andThen(fn));
|
||||
},
|
||||
'.or': () => {
|
||||
const optb = Some('bar');
|
||||
assertEquivalent(Some('foo'), Some('foo').or(optb));
|
||||
assertEquivalent(optb, None.or(optb));
|
||||
},
|
||||
'.orElse': () => {
|
||||
const fn = () => Some('bar');
|
||||
assertEquivalent(Some('foo'), Some('foo').orElse(fn));
|
||||
assertEquivalent(Some('bar'), None.orElse(fn));
|
||||
},
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
@ -132,8 +132,47 @@ export const Ansi = {
|
||||
moveCursorDown,
|
||||
textFormat,
|
||||
color,
|
||||
colors: {
|
||||
rgb,
|
||||
Black: AnsiColor.FgBlack,
|
||||
Red: AnsiColor.FgRed,
|
||||
Green: AnsiColor.FgGreen,
|
||||
Yellow: AnsiColor.FgYellow,
|
||||
Blue: AnsiColor.FgBlue,
|
||||
Magenta: AnsiColor.FgMagenta,
|
||||
Cyan: AnsiColor.FgCyan,
|
||||
White: AnsiColor.FgWhite,
|
||||
BrightBlack: AnsiColor.FgBrightBlack,
|
||||
BrightRed: AnsiColor.FgBrightRed,
|
||||
BrightGreen: AnsiColor.FgBrightGreen,
|
||||
BrightYellow: AnsiColor.FgBrightYellow,
|
||||
BrightBlue: AnsiColor.FgBrightBlue,
|
||||
BrightMagenta: AnsiColor.FgBrightMagenta,
|
||||
BrightCyan: AnsiColor.FgBrightCyan,
|
||||
BrightWhite: AnsiColor.FgBrightWhite,
|
||||
Invert: AnsiColor.Invert,
|
||||
background: {
|
||||
rgb: (r: number, g: number, b: number) => rgb(r, g, b, Ground.Back),
|
||||
Black: AnsiColor.BgBlack,
|
||||
Red: AnsiColor.BgRed,
|
||||
Green: AnsiColor.BgGreen,
|
||||
Yellow: AnsiColor.BgYellow,
|
||||
Blue: AnsiColor.BgBlue,
|
||||
Magenta: AnsiColor.BgMagenta,
|
||||
Cyan: AnsiColor.BgCyan,
|
||||
White: AnsiColor.BgWhite,
|
||||
BrightBlack: AnsiColor.BgBrightBlack,
|
||||
BrightRed: AnsiColor.BgBrightRed,
|
||||
BrightGreen: AnsiColor.BgBrightGreen,
|
||||
BrightYellow: AnsiColor.BgBrightYellow,
|
||||
BrightBlue: AnsiColor.BgBrightBlue,
|
||||
BrightMagenta: AnsiColor.BgBrightMagenta,
|
||||
BrightCyan: AnsiColor.BgBrightCyan,
|
||||
BrightWhite: AnsiColor.BgBrightWhite,
|
||||
Invert: AnsiColor.Invert,
|
||||
},
|
||||
},
|
||||
color256,
|
||||
rgb,
|
||||
};
|
||||
|
||||
export default Ansi;
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { ITerminalSize } from './types.ts';
|
||||
import Ansi from './ansi.ts';
|
||||
import { HighlightType, ITerminalSize } from './types.ts';
|
||||
|
||||
export const SCROLL_VERSION = '0.0.1';
|
||||
export const SCROLL_QUIT_TIMES = 3;
|
||||
@ -11,3 +12,16 @@ export const defaultTerminalSize: ITerminalSize = {
|
||||
rows: 24,
|
||||
cols: 80,
|
||||
};
|
||||
|
||||
export const SCROLL_COLOR_SCHEME: Map<HighlightType, string> = new Map([
|
||||
[HighlightType.Match, Ansi.colors.Invert.toString()], // Inverted color
|
||||
[HighlightType.Number, Ansi.color256(196)], // Bright Red
|
||||
[HighlightType.Character, Ansi.color256(207)], // Magenta
|
||||
[HighlightType.String, Ansi.color256(45)], // Cyan
|
||||
[HighlightType.SingleLineComment, Ansi.color256(248)], // Light Gray
|
||||
[HighlightType.MultiLineComment, Ansi.color256(240)], // Medium-light Gray
|
||||
[HighlightType.Keyword1, Ansi.color256(226)], // Yellow
|
||||
[HighlightType.Keyword2, Ansi.color256(118)], // Green
|
||||
[HighlightType.Operator, Ansi.color256(215)], // Orange/Brown
|
||||
[HighlightType.None, Ansi.ResetFormatting],
|
||||
]);
|
||||
|
@ -9,22 +9,16 @@ export class Document {
|
||||
/**
|
||||
* Each line of the current document
|
||||
*/
|
||||
#rows: Row[];
|
||||
#rows: Row[] = [];
|
||||
|
||||
/**
|
||||
* Has the document been modified?
|
||||
* @param dirty - Has the document been modified?
|
||||
* @param type - The meta-data for the file type of the current document
|
||||
*/
|
||||
public dirty: boolean;
|
||||
|
||||
/**
|
||||
* The meta-data for the file type of the current document
|
||||
*/
|
||||
public type: FileType;
|
||||
|
||||
private constructor() {
|
||||
this.#rows = [];
|
||||
this.dirty = false;
|
||||
this.type = FileType.default();
|
||||
private constructor(
|
||||
public dirty: boolean = false,
|
||||
public type: FileType = FileType.default(),
|
||||
) {
|
||||
}
|
||||
|
||||
public get fileType(): string {
|
||||
|
@ -325,7 +325,7 @@ export default class Editor {
|
||||
const screenHeight = this.screen.rows;
|
||||
let { x, y } = this.cursor;
|
||||
const height = this.numRows;
|
||||
let width = (this.row(y).isSome()) ? this.row(y).unwrap().size : 0;
|
||||
let width = this.row(y).mapOr(0, (r) => r.size);
|
||||
|
||||
switch (char) {
|
||||
case KeyCommand.ArrowUp:
|
||||
@ -370,7 +370,7 @@ export default class Editor {
|
||||
break;
|
||||
}
|
||||
|
||||
width = (this.row(y).isSome()) ? this.row(y).unwrap().size : 0;
|
||||
width = this.row(y).mapOr(0, (r) => r.size);
|
||||
|
||||
if (x > width) {
|
||||
x = width;
|
||||
@ -383,9 +383,10 @@ export default class Editor {
|
||||
* Calculate the window of a file to display
|
||||
*/
|
||||
protected scroll(): void {
|
||||
this.renderX = (this.row(this.cursor.y).isSome())
|
||||
? this.row(this.cursor.y).unwrap().cxToRx(this.cursor.x)
|
||||
: 0;
|
||||
this.renderX = this.row(this.cursor.y).mapOr(
|
||||
0,
|
||||
(r) => r.cxToRx(this.cursor.x),
|
||||
);
|
||||
|
||||
const { y } = this.cursor;
|
||||
const offset = this.offset;
|
||||
|
@ -3,6 +3,7 @@ import { AbstractFileType } from './base.ts';
|
||||
import { CFile } from './c.ts';
|
||||
import { CSSFile } from './css.ts';
|
||||
import { JavaScriptFile, TypeScriptFile } from './javascript.ts';
|
||||
import { RustFile } from './rust.ts';
|
||||
import { ShellFile } from './shell.ts';
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@ -10,14 +11,15 @@ import { ShellFile } from './shell.ts';
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
export const fileTypeMap = new Map([
|
||||
['.bash', ShellFile],
|
||||
['.c', CFile],
|
||||
['.h', CFile],
|
||||
['.css', CSSFile],
|
||||
['.json', JavaScriptFile],
|
||||
['.h', CFile],
|
||||
['.js', JavaScriptFile],
|
||||
['.json', JavaScriptFile],
|
||||
['.jsx', JavaScriptFile],
|
||||
['.mjs', JavaScriptFile],
|
||||
['.bash', ShellFile],
|
||||
['.rs', RustFile],
|
||||
['.sh', ShellFile],
|
||||
['.ts', TypeScriptFile],
|
||||
['.tsx', TypeScriptFile],
|
||||
|
169
src/common/filetype/rust.ts
Normal file
169
src/common/filetype/rust.ts
Normal file
@ -0,0 +1,169 @@
|
||||
import Option, { Some } from '../option.ts';
|
||||
import {
|
||||
AbstractFileType,
|
||||
defaultHighlightOptions,
|
||||
FileLang,
|
||||
HighlightingOptions,
|
||||
} from './base.ts';
|
||||
|
||||
export class RustFile extends AbstractFileType {
|
||||
public readonly name: FileLang = FileLang.Rust;
|
||||
public readonly singleLineComment = Some('//');
|
||||
public readonly multiLineCommentStart: Option<string> = Some('/*');
|
||||
public readonly multiLineCommentEnd: Option<string> = Some('*/');
|
||||
public readonly keywords1 = [
|
||||
'continue',
|
||||
'return',
|
||||
'static',
|
||||
'struct',
|
||||
'unsafe',
|
||||
'break',
|
||||
'const',
|
||||
'crate',
|
||||
'extern',
|
||||
'match',
|
||||
'super',
|
||||
'trait',
|
||||
'where',
|
||||
'else',
|
||||
'enum',
|
||||
'false',
|
||||
'impl',
|
||||
'loop',
|
||||
'move',
|
||||
'self',
|
||||
'type',
|
||||
'while',
|
||||
'for',
|
||||
'let',
|
||||
'mod',
|
||||
'pub',
|
||||
'ref',
|
||||
'true',
|
||||
'use',
|
||||
'mut',
|
||||
'as',
|
||||
'fn',
|
||||
'if',
|
||||
'in',
|
||||
];
|
||||
public readonly keywords2 = [
|
||||
'DoubleEndedIterator',
|
||||
'ExactSizeIterator',
|
||||
'IntoIterator',
|
||||
'PartialOrd',
|
||||
'PartialEq',
|
||||
'Iterator',
|
||||
'ToString',
|
||||
'Default',
|
||||
'ToOwned',
|
||||
'Extend',
|
||||
'FnOnce',
|
||||
'Option',
|
||||
'String',
|
||||
'AsMut',
|
||||
'AsRef',
|
||||
'Clone',
|
||||
'Debug',
|
||||
'FnMut',
|
||||
'Sized',
|
||||
'Unpin',
|
||||
'array',
|
||||
'isize',
|
||||
'usize',
|
||||
'&str',
|
||||
'Copy',
|
||||
'Drop',
|
||||
'From',
|
||||
'Into',
|
||||
'None',
|
||||
'Self',
|
||||
'Send',
|
||||
'Some',
|
||||
'Sync',
|
||||
'bool',
|
||||
'char',
|
||||
'i128',
|
||||
'u128',
|
||||
'Box',
|
||||
'Err',
|
||||
'Ord',
|
||||
'Vec',
|
||||
'dyn',
|
||||
'f32',
|
||||
'f64',
|
||||
'i16',
|
||||
'i32',
|
||||
'i64',
|
||||
'str',
|
||||
'u16',
|
||||
'u32',
|
||||
'u64',
|
||||
'Eq',
|
||||
'Fn',
|
||||
'Ok',
|
||||
'i8',
|
||||
'u8',
|
||||
'&mut self',
|
||||
'&mut',
|
||||
'&self',
|
||||
'self',
|
||||
];
|
||||
public readonly operators = [
|
||||
'||=',
|
||||
'>>=',
|
||||
'<=>',
|
||||
'<<=',
|
||||
'&&=',
|
||||
'**=',
|
||||
'..=',
|
||||
'...',
|
||||
'||',
|
||||
'|=',
|
||||
'>>',
|
||||
'>=',
|
||||
'=>',
|
||||
'==',
|
||||
'<=',
|
||||
'<<',
|
||||
'<-',
|
||||
'+=',
|
||||
'++',
|
||||
'^=',
|
||||
'%=',
|
||||
'&=',
|
||||
'&&',
|
||||
'/=',
|
||||
'*=',
|
||||
'**',
|
||||
'..',
|
||||
'!=',
|
||||
':=',
|
||||
'::',
|
||||
'->',
|
||||
'-=',
|
||||
'--',
|
||||
'~',
|
||||
'|',
|
||||
'>',
|
||||
'=',
|
||||
'<',
|
||||
'+',
|
||||
'^',
|
||||
'%',
|
||||
'&',
|
||||
'*',
|
||||
'.',
|
||||
'!',
|
||||
':',
|
||||
';',
|
||||
',',
|
||||
'-',
|
||||
];
|
||||
public readonly hlOptions: HighlightingOptions = {
|
||||
...defaultHighlightOptions,
|
||||
characters: true,
|
||||
binNumbers: true,
|
||||
hexNumbers: true,
|
||||
};
|
||||
}
|
@ -1,48 +1,38 @@
|
||||
import Ansi from './ansi.ts';
|
||||
import { SCROLL_COLOR_SCHEME } from './config.ts';
|
||||
|
||||
/**
|
||||
* The type of Syntax being highlighted
|
||||
*/
|
||||
export enum HighlightType {
|
||||
/** No highlighting */
|
||||
None,
|
||||
/** Number literals */
|
||||
Number,
|
||||
/** Search results */
|
||||
Match,
|
||||
/** Character literals */
|
||||
Character,
|
||||
/** String literals */
|
||||
String,
|
||||
/** Single line comments */
|
||||
SingleLineComment,
|
||||
/** Multi-line comments */
|
||||
MultiLineComment,
|
||||
/** Primary keywords */
|
||||
Keyword1,
|
||||
/** Secondary keywords */
|
||||
Keyword2,
|
||||
/** Math/logic operators */
|
||||
Operator,
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the configured ANSI formatting escape codes for the
|
||||
* type of syntax specified
|
||||
*
|
||||
* @param type The type of syntax to highlight
|
||||
*/
|
||||
export function highlightToColor(type: HighlightType): string {
|
||||
switch (type) {
|
||||
case HighlightType.Number:
|
||||
return Ansi.color256(196);
|
||||
|
||||
case HighlightType.Match:
|
||||
return Ansi.color256(21);
|
||||
|
||||
case HighlightType.Character:
|
||||
return Ansi.color256(207);
|
||||
|
||||
case HighlightType.String:
|
||||
return Ansi.color256(45);
|
||||
|
||||
case HighlightType.SingleLineComment:
|
||||
return Ansi.color256(248);
|
||||
|
||||
case HighlightType.MultiLineComment:
|
||||
return Ansi.color256(240);
|
||||
|
||||
case HighlightType.Keyword1:
|
||||
return Ansi.color256(226);
|
||||
|
||||
case HighlightType.Keyword2:
|
||||
return Ansi.color256(118);
|
||||
|
||||
case HighlightType.Operator:
|
||||
return Ansi.color256(215);
|
||||
|
||||
default:
|
||||
return Ansi.ResetFormatting;
|
||||
}
|
||||
return SCROLL_COLOR_SCHEME.get(type) ?? Ansi.ResetFormatting;
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
export { HighlightType } from './highlight.ts';
|
||||
export { Position } from './position.ts';
|
||||
export type { ITestBase } from './runtime/test_base.ts';
|
||||
export type {
|
||||
|
Loading…
Reference in New Issue
Block a user