Skip to content

Commit 55ab234

Browse files
committed
compiler: Have a key-sequence type
... which is lowered to a string for now.
1 parent 652fab4 commit 55ab234

28 files changed

+326
-17
lines changed

internal/compiler/builtin_macros.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,12 @@ fn to_debug_string(
322322
Type::Float32 | Type::Int32 => expr.maybe_convert_to(Type::String, node, diag),
323323
Type::String => expr,
324324
// TODO
325-
Type::Color | Type::Brush | Type::Image | Type::Easing | Type::Array(_) => {
325+
Type::Color
326+
| Type::Brush
327+
| Type::Image
328+
| Type::Easing
329+
| Type::Array(_)
330+
| Type::KeyboardShortcut => {
326331
Expression::StringLiteral("<debug-of-this-type-not-yet-implemented>".into())
327332
}
328333
Type::Duration

internal/compiler/expression_tree.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
33

44
use crate::diagnostics::{BuildDiagnostics, SourceLocation, Spanned};
5-
use crate::langtype::{BuiltinElement, EnumerationValue, Function, Struct, Type};
5+
use crate::langtype::{BuiltinElement, EnumerationValue, Function, KeyboardShortcut, Struct, Type};
66
use crate::layout::Orientation;
77
use crate::lookup::LookupCtx;
88
use crate::object_tree::*;
@@ -723,6 +723,8 @@ pub enum Expression {
723723

724724
EnumerationValue(EnumerationValue),
725725

726+
KeyboardShortcut(Vec<KeyboardShortcut>),
727+
726728
ReturnStatement(Option<Box<Expression>>),
727729

728730
LayoutCacheAccess {
@@ -863,6 +865,7 @@ impl Expression {
863865
Expression::LinearGradient { .. } => Type::Brush,
864866
Expression::RadialGradient { .. } => Type::Brush,
865867
Expression::EnumerationValue(value) => Type::Enumeration(value.enumeration.clone()),
868+
Expression::KeyboardShortcut(_) => Type::KeyboardShortcut,
866869
// invalid because the expression is unreachable
867870
Expression::ReturnStatement(_) => Type::Invalid,
868871
Expression::LayoutCacheAccess { .. } => Type::LogicalLength,
@@ -952,6 +955,7 @@ impl Expression {
952955
}
953956
}
954957
Expression::EnumerationValue(_) => {}
958+
Expression::KeyboardShortcut(_) => {}
955959
Expression::ReturnStatement(expr) => {
956960
expr.as_deref().map(visitor);
957961
}
@@ -1049,6 +1053,7 @@ impl Expression {
10491053
}
10501054
}
10511055
Expression::EnumerationValue(_) => {}
1056+
Expression::KeyboardShortcut(_) => {}
10521057
Expression::ReturnStatement(expr) => {
10531058
expr.as_deref_mut().map(visitor);
10541059
}
@@ -1135,6 +1140,7 @@ impl Expression {
11351140
stops.iter().all(|(c, s)| c.is_constant() && s.is_constant())
11361141
}
11371142
Expression::EnumerationValue(_) => true,
1143+
Expression::KeyboardShortcut(_) => true,
11381144
Expression::ReturnStatement(expr) => {
11391145
expr.as_ref().map_or(true, |expr| expr.is_constant())
11401146
}
@@ -1377,6 +1383,7 @@ impl Expression {
13771383
Type::Enumeration(enumeration) => {
13781384
Expression::EnumerationValue(enumeration.clone().default_value())
13791385
}
1386+
Type::KeyboardShortcut => Expression::KeyboardShortcut(vec![]),
13801387
Type::ComponentFactory => Expression::EmptyComponentFactory,
13811388
}
13821389
}
@@ -1757,6 +1764,13 @@ pub fn pretty_print(f: &mut dyn std::fmt::Write, expression: &Expression) -> std
17571764
Some(val) => write!(f, "{}.{}", e.enumeration.name, val),
17581765
None => write!(f, "{}.{}", e.enumeration.name, e.value),
17591766
},
1767+
Expression::KeyboardShortcut(ks) => {
1768+
if ks.is_empty() {
1769+
write!(f, "@keys()")
1770+
} else {
1771+
todo!()
1772+
}
1773+
}
17601774
Expression::ReturnStatement(e) => {
17611775
write!(f, "return ")?;
17621776
e.as_ref().map(|e| pretty_print(f, e)).unwrap_or(Ok(()))

internal/compiler/generator/cpp.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ pub mod cpp_ast {
116116

117117
use smol_str::{format_smolstr, SmolStr};
118118

119-
thread_local!(static INDENTATION : Cell<u32> = Cell::new(0));
119+
thread_local!(static INDENTATION : Cell<u32> = const { Cell::new(0) });
120120
fn indent(f: &mut Formatter<'_>) -> Result<(), Error> {
121121
INDENTATION.with(|i| {
122122
for _ in 0..(i.get()) {
@@ -167,7 +167,7 @@ pub mod cpp_ast {
167167
Some(Declaration::Var(Var {
168168
ty: var.ty.clone(),
169169
name: var.name.clone(),
170-
array_size: var.array_size.clone(),
170+
array_size: var.array_size,
171171
init: std::mem::take(&mut var.init),
172172
is_extern: false,
173173
..Default::default()
@@ -506,7 +506,7 @@ impl CppType for Type {
506506
Type::Void => Some("void".into()),
507507
Type::Float32 => Some("float".into()),
508508
Type::Int32 => Some("int".into()),
509-
Type::String => Some("slint::SharedString".into()),
509+
Type::String | Type::KeyboardShortcut => Some("slint::SharedString".into()),
510510
Type::Color => Some("slint::Color".into()),
511511
Type::Duration => Some("std::int64_t".into()),
512512
Type::Angle => Some("float".into()),
@@ -560,7 +560,7 @@ fn remove_parentheses(expr: &str) -> &str {
560560
if expr.starts_with('(') && expr.ends_with(')') {
561561
let mut level = 0;
562562
// check that the opening and closing parentheses are on the same level
563-
for byte in expr[1..expr.len() - 1].as_bytes() {
563+
for byte in &expr.as_bytes()[1..expr.len() - 1] {
564564
match byte {
565565
b')' if level == 0 => return expr,
566566
b')' => level -= 1,
@@ -873,7 +873,7 @@ pub fn generate(
873873

874874
for (cpp_file_name, cpp_file) in config.cpp_files.iter().zip(cpp_files) {
875875
use std::io::Write;
876-
write!(&mut BufWriter::new(std::fs::File::create(&cpp_file_name)?), "{cpp_file}")?;
876+
write!(&mut BufWriter::new(std::fs::File::create(cpp_file_name)?), "{cpp_file}")?;
877877
}
878878

879879
Ok(file)
@@ -2220,7 +2220,7 @@ fn generate_sub_component(
22202220
" if (!self->{name}.running() || self->{name}.interval() != interval)"
22212221
));
22222222
update_timers.push(format!(" self->{name}.start(slint::TimerMode::Repeated, interval, [self] {{ {callback}; }});"));
2223-
update_timers.push(format!("}} else {{ self->{name}.stop(); }}").into());
2223+
update_timers.push(format!("}} else {{ self->{name}.stop(); }}"));
22242224
target_struct.members.push((
22252225
field_access,
22262226
Declaration::Var(Var { ty: "slint::Timer".into(), name, ..Default::default() }),
@@ -3131,7 +3131,7 @@ fn compile_expression(expr: &llr::Expression, ctx: &EvaluationContext) -> String
31313131
let item_rc = access_item_rc(function, ctx);
31323132
let window = access_window_field(ctx);
31333133
let (native, name) = native_prop_info(function, ctx);
3134-
let function_name = format!("slint_{}_{}", native.class_name.to_lowercase(), ident(&name).to_lowercase());
3134+
let function_name = format!("slint_{}_{}", native.class_name.to_lowercase(), ident(name).to_lowercase());
31353135
format!("{function_name}(&{item}, &{window}.handle(), &{item_rc})")
31363136
}
31373137
Expression::ExtraBuiltinFunctionCall { function, arguments, return_ty: _ } => {
@@ -4002,7 +4002,7 @@ fn compile_builtin_function_call(
40024002
"self->update_timers()".into()
40034003
}
40044004
BuiltinFunction::DetectOperatingSystem => {
4005-
format!("slint::cbindgen_private::slint_detect_operating_system()")
4005+
"slint::cbindgen_private::slint_detect_operating_system()".to_string()
40064006
}
40074007
// start and stop are unreachable because they are lowered to simple assignment of running
40084008
BuiltinFunction::StartTimer => unreachable!(),

internal/compiler/generator/rust.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ pub fn rust_primitive_type(ty: &Type) -> Option<proc_macro2::TokenStream> {
8181
Type::Void => Some(quote!(())),
8282
Type::Int32 => Some(quote!(i32)),
8383
Type::Float32 => Some(quote!(f32)),
84-
Type::String => Some(quote!(sp::SharedString)),
84+
Type::String | Type::KeyboardShortcut => Some(quote!(sp::SharedString)),
8585
Type::Color => Some(quote!(sp::Color)),
8686
Type::ComponentFactory => Some(quote!(slint::ComponentFactory)),
8787
Type::Duration => Some(quote!(i64)),

internal/compiler/langtype.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ pub enum Type {
5454
Array(Rc<Type>),
5555
Struct(Rc<Struct>),
5656
Enumeration(Rc<Enumeration>),
57+
KeyboardShortcut,
5758

5859
/// A type made up of the product of several "unit" types.
5960
/// The first parameter is the unit, and the second parameter is the power.
@@ -101,6 +102,7 @@ impl core::cmp::PartialEq for Type {
101102
matches!(other, Type::Struct(rhs) if lhs.fields == rhs.fields && lhs.name == rhs.name)
102103
}
103104
Type::Enumeration(lhs) => matches!(other, Type::Enumeration(rhs) if lhs == rhs),
105+
Type::KeyboardShortcut => matches!(other, Type::KeyboardShortcut),
104106
Type::UnitProduct(a) => matches!(other, Type::UnitProduct(b) if a == b),
105107
Type::ElementReference => matches!(other, Type::ElementReference),
106108
Type::LayoutCache => matches!(other, Type::LayoutCache),
@@ -160,6 +162,7 @@ impl Display for Type {
160162
Type::Easing => write!(f, "easing"),
161163
Type::Brush => write!(f, "brush"),
162164
Type::Enumeration(enumeration) => write!(f, "enum {}", enumeration.name),
165+
Type::KeyboardShortcut => write!(f, "keyboard-shortcut"),
163166
Type::UnitProduct(vec) => {
164167
const POWERS: &[char] = &['⁰', '¹', '²', '³', '⁴', '⁵', '⁶', '⁷', '⁸', '⁹'];
165168
let mut x = vec.iter().map(|(unit, power)| {
@@ -208,6 +211,7 @@ impl Type {
208211
| Self::Bool
209212
| Self::Easing
210213
| Self::Enumeration(_)
214+
| Self::KeyboardShortcut
211215
| Self::ElementReference
212216
| Self::Struct { .. }
213217
| Self::Array(_)
@@ -265,6 +269,7 @@ impl Type {
265269
| (Type::LogicalLength, Type::Rem)
266270
| (Type::PhysicalLength, Type::Rem)
267271
| (Type::Percent, Type::Float32)
272+
| (Type::KeyboardShortcut, Type::String)
268273
| (Type::Brush, Type::Color)
269274
| (Type::Color, Type::Brush) => true,
270275
(Type::Array(a), Type::Model) if a.is_property_type() => true,
@@ -311,6 +316,7 @@ impl Type {
311316
Type::Array(_) => None,
312317
Type::Struct { .. } => None,
313318
Type::Enumeration(_) => None,
319+
Type::KeyboardShortcut => None,
314320
Type::UnitProduct(_) => None,
315321
Type::ElementReference => None,
316322
Type::LayoutCache => None,
@@ -839,6 +845,40 @@ impl Enumeration {
839845
}
840846
}
841847

848+
#[derive(Clone, Debug, Default)]
849+
pub struct KeyboardModifiers {
850+
pub alt: bool,
851+
pub control: bool,
852+
pub meta: bool,
853+
pub shift: bool,
854+
}
855+
856+
#[derive(Clone, Debug, Default)]
857+
pub struct KeyboardShortcut {
858+
pub key: String,
859+
pub modifiers: KeyboardModifiers,
860+
}
861+
862+
impl PartialEq for KeyboardShortcut {
863+
fn eq(&self, _other: &Self) -> bool {
864+
true
865+
}
866+
}
867+
868+
impl std::fmt::Display for KeyboardShortcut {
869+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
870+
let alt = if self.modifiers.alt { "alt+" } else { "" };
871+
let ctrl = if self.modifiers.control { "ctrl+" } else { "" };
872+
let meta = if self.modifiers.meta { "meta+" } else { "" };
873+
let shift = if self.modifiers.shift { "shift+" } else { "" };
874+
write!(f, "{alt}{ctrl}{meta}{shift}{}", self.key)
875+
}
876+
}
877+
878+
pub fn keyboard_shortcuts_to_string(shortcuts: &[KeyboardShortcut]) -> String {
879+
shortcuts.iter().map(|ks| ks.to_string()).join(", ")
880+
}
881+
842882
#[derive(Clone, Debug)]
843883
pub struct EnumerationValue {
844884
pub value: usize, // index in enumeration.values

internal/compiler/llr/expression.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,7 @@ impl Expression {
259259
Type::Enumeration(enumeration) => {
260260
Expression::EnumerationValue(enumeration.clone().default_value())
261261
}
262+
Type::KeyboardShortcut => Expression::StringLiteral(SmolStr::new_static("")),
262263
Type::ComponentFactory => Expression::EmptyComponentFactory,
263264
})
264265
}

internal/compiler/llr/lower_expression.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use smol_str::{format_smolstr, SmolStr};
1212
use super::lower_to_item_tree::{LoweredElement, LoweredSubComponentMapping, LoweringState};
1313
use super::{Animation, PropertyIdx, PropertyReference, RepeatedElementIdx};
1414
use crate::expression_tree::{BuiltinFunction, Callable, Expression as tree_Expression};
15-
use crate::langtype::{EnumerationValue, Struct, Type};
15+
use crate::langtype::{self, EnumerationValue, Struct, Type};
1616
use crate::layout::Orientation;
1717
use crate::llr::Expression as llr_Expression;
1818
use crate::namedreference::NamedReference;
@@ -234,6 +234,9 @@ pub fn lower_expression(
234234
.collect::<_>(),
235235
},
236236
tree_Expression::EnumerationValue(e) => llr_Expression::EnumerationValue(e.clone()),
237+
tree_Expression::KeyboardShortcut(ks) => {
238+
llr_Expression::StringLiteral(SmolStr::from(langtype::keyboard_shortcuts_to_string(ks)))
239+
}
237240
tree_Expression::ReturnStatement(..) => {
238241
panic!("The remove return pass should have removed all return")
239242
}

internal/compiler/lookup.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -632,7 +632,7 @@ impl ColorSpecific {
632632
}
633633
}
634634

635-
struct KeysLookup;
635+
pub struct KeysLookup;
636636

637637
macro_rules! special_keys_lookup {
638638
($($char:literal # $name:ident # $($qt:ident)|* # $($winit:ident $(($_pos:ident))?)|* # $($_xkb:ident)|*;)*) => {

internal/compiler/parser.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -374,7 +374,7 @@ declare_syntax! {
374374
Expression-> [ ?Expression, ?FunctionCallExpression, ?IndexExpression, ?SelfAssignment,
375375
?ConditionalExpression, ?QualifiedName, ?BinaryExpression, ?Array, ?ObjectLiteral,
376376
?UnaryOpExpression, ?CodeBlock, ?StringTemplate, ?AtImageUrl, ?AtGradient, ?AtTr,
377-
?MemberAccess ],
377+
?MemberAccess, ?AtKeys ],
378378
/// Concatenate the Expressions to make a string (usually expended from a template string)
379379
StringTemplate -> [*Expression],
380380
/// `@image-url("foo.png")`
@@ -387,6 +387,8 @@ declare_syntax! {
387387
TrContext -> [],
388388
/// `| "foo" % n` in a `AtTr` node
389389
TrPlural -> [Expression],
390+
/// `@keys(...)`
391+
AtKeys -> [],
390392
/// expression()
391393
FunctionCallExpression -> [*Expression],
392394
/// `expression[index]`

0 commit comments

Comments
 (0)