Lint vertical spacing in the code (#3224)

* Lint vertical spacing in the code

* Add some vertical spacing for readability
This commit is contained in:
Emil Ernerfeldt 2023-08-10 15:26:54 +02:00 committed by GitHub
parent 83c18498e9
commit d568d9f5d0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 215 additions and 14 deletions

View File

@ -1,6 +1,6 @@
on: [push, pull_request]
name: CI
name: Rust
env:
# web_sys_unstable_apis is required to enable the web_sys clipboard API which eframe web uses,
@ -37,6 +37,9 @@ jobs:
- name: Rustfmt
run: cargo fmt --all -- --check
- name: Lint vertical spacing
run: ./scripts/lint.py
- name: Install cargo-cranky
uses: baptiste0928/cargo-install@v1
with:
@ -145,7 +148,7 @@ jobs:
rust-version: "1.65.0"
log-level: error
command: check
arguments: ${{ matrix.flags }} --target ${{ matrix.target }}
arguments: --target ${{ matrix.target }}
# ---------------------------------------------------------------------------

View File

@ -60,7 +60,7 @@ Read the section on integrations at <https://github.com/emilk/egui#integrations>
## Code Conventions
Conventions unless otherwise specified:
* angles are in radians
* angles are in radians and clock-wise
* `Vec2::X` is right and `Vec2::Y` is down.
* `Pos2::ZERO` is left top.

View File

@ -272,6 +272,7 @@ pub fn run_simple_native(
struct SimpleApp<U> {
update_fun: U,
}
impl<U: FnMut(&egui::Context, &mut Frame)> App for SimpleApp<U> {
fn update(&mut self, ctx: &egui::Context, frame: &mut Frame) {
(self.update_fun)(ctx, frame);

View File

@ -335,8 +335,10 @@ pub struct EpiIntegration {
pub egui_ctx: egui::Context,
pending_full_output: egui::FullOutput,
egui_winit: egui_winit::State,
/// When set, it is time to close the native window.
close: bool,
can_drag_window: bool,
window_state: WindowState,
follow_system_theme: bool,

View File

@ -22,6 +22,7 @@ use super::epi_integration::{self, EpiIntegration};
pub enum UserEvent {
RequestRepaint {
when: Instant,
/// What the frame number was when the repaint was _requested_.
frame_nr: u64,
},

View File

@ -334,16 +334,22 @@ struct Prepared {
state: State,
has_bar: [bool; 2],
auto_shrink: [bool; 2],
/// How much horizontal and vertical space are used up by the
/// width of the vertical bar, and the height of the horizontal bar?
current_bar_use: Vec2,
scroll_bar_visibility: ScrollBarVisibility,
/// Where on the screen the content is (excludes scroll bars).
inner_rect: Rect,
content_ui: Ui,
/// Relative coordinates: the offset and size of the view of the inner UI.
/// `viewport.min == ZERO` means we scrolled to the top.
viewport: Rect,
scrolling_enabled: bool,
stick_to_end: [bool; 2],
}

View File

@ -693,27 +693,37 @@ pub enum Key {
/// The virtual keycode for the Minus key.
Minus,
/// The virtual keycode for the Plus/Equals key.
PlusEquals,
/// Either from the main row or from the numpad.
Num0,
/// Either from the main row or from the numpad.
Num1,
/// Either from the main row or from the numpad.
Num2,
/// Either from the main row or from the numpad.
Num3,
/// Either from the main row or from the numpad.
Num4,
/// Either from the main row or from the numpad.
Num5,
/// Either from the main row or from the numpad.
Num6,
/// Either from the main row or from the numpad.
Num7,
/// Either from the main row or from the numpad.
Num8,
/// Either from the main row or from the numpad.
Num9,

View File

@ -60,6 +60,7 @@ pub(crate) struct GridLayout {
/// State previous frame (if any).
/// This can be used to predict future sizes of cells.
prev_state: State,
/// State accumulated during the current frame.
curr_state: State,
initial_available: Rect,

View File

@ -546,8 +546,10 @@ impl Memory {
#[cfg_attr(feature = "serde", serde(default))]
pub struct Areas {
areas: IdMap<area::State>,
/// Back-to-front. Top is last.
order: Vec<LayerId>,
visible_last_frame: ahash::HashSet<LayerId>,
visible_current_frame: ahash::HashSet<LayerId>,

View File

@ -23,6 +23,7 @@ pub struct Button {
text: WidgetText,
shortcut_text: WidgetText,
wrap: Option<bool>,
/// None means default for interact
fill: Option<Color32>,
stroke: Option<Stroke>,

View File

@ -11,6 +11,7 @@ use crate::*;
pub(crate) struct MonoState {
last_dragged_id: Option<Id>,
last_dragged_value: Option<f64>,
/// For temporary edit of a [`DragValue`] value.
/// Couples with the current focus id.
edit_string: Option<String>,

View File

@ -760,15 +760,22 @@ impl PlotItem for Text {
/// A set of points.
pub struct Points {
pub(super) series: PlotPoints,
pub(super) shape: MarkerShape,
/// Color of the marker. `Color32::TRANSPARENT` means that it will be picked automatically.
pub(super) color: Color32,
/// Whether to fill the marker. Does not apply to all types.
pub(super) filled: bool,
/// The maximum extent of the marker from its center.
pub(super) radius: f32,
pub(super) name: String,
pub(super) highlight: bool,
pub(super) stems: Option<f32>,
}
@ -1290,8 +1297,10 @@ pub struct BarChart {
pub(super) bars: Vec<Bar>,
pub(super) default_color: Color32,
pub(super) name: String,
/// A custom element formatter
pub(super) element_formatter: Option<Box<dyn Fn(&Bar, &BarChart) -> String>>,
highlight: bool,
}
@ -1460,8 +1469,10 @@ pub struct BoxPlot {
pub(super) boxes: Vec<BoxElem>,
pub(super) default_color: Color32,
pub(super) name: String,
/// A custom element formatter
pub(super) element_formatter: Option<Box<dyn Fn(&BoxElem, &BoxPlot) -> String>>,
highlight: bool,
}

View File

@ -101,9 +101,11 @@ struct PlotMemory {
/// Indicates if the user has modified the bounds, for example by moving or zooming,
/// or if the bounds should be calculated based by included point or auto bounds.
bounds_modified: AxisBools,
hovered_entry: Option<String>,
hidden_items: ahash::HashSet<String>,
last_plot_transform: PlotTransform,
/// Allows to remember the first click position when performing a boxed zoom
last_click_pos_for_zoom: Option<Pos2>,
}

View File

@ -77,8 +77,10 @@ pub struct Slider<'a> {
prefix: String,
suffix: String,
text: WidgetText,
/// Sets the minimal step of the widget value
step: Option<f64>,
drag_value_speed: Option<f64>,
min_decimals: usize,
max_decimals: Option<usize>,

View File

@ -10,11 +10,15 @@ pub use usvg::FitTo;
/// Use the `svg` and `image` features to enable more constructors.
pub struct RetainedImage {
debug_name: String,
size: [usize; 2],
/// Cleared once [`Self::texture`] has been loaded.
image: Mutex<egui::ColorImage>,
/// Lazily loaded when we have an egui context.
texture: Mutex<Option<egui::TextureHandle>>,
options: TextureOptions,
}

View File

@ -32,9 +32,11 @@ pub struct StripLayout<'l> {
direction: CellDirection,
pub(crate) rect: Rect,
pub(crate) cursor: Pos2,
/// Keeps track of the max used position,
/// so we know how much space we used.
max: Pos2,
cell_layout: egui::Layout,
}

View File

@ -28,7 +28,9 @@ enum InitialColumnSize {
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Column {
initial_width: InitialColumnSize,
width_range: Rangef,
/// Clip contents if too narrow?
clip: bool,
@ -511,8 +513,10 @@ pub struct Table<'a> {
columns: Vec<Column>,
available_width: f32,
state: TableState,
/// Accumulated maximum used widths for each column.
max_used_widths: Vec<f32>,
first_frame_auto_size_columns: bool,
resizable: bool,
striped: bool,
@ -1011,8 +1015,10 @@ pub struct TableRow<'a, 'b> {
layout: &'b mut StripLayout<'a>,
columns: &'b [Column],
widths: &'b [f32],
/// grows during building with the maximum widths
max_used_widths: &'b mut [f32],
col_index: usize,
striped: bool,
height: f32,

View File

@ -13,17 +13,15 @@ use emath::*;
#[allow(clippy::approx_constant)]
mod precomputed_vertices {
/*
fn main() {
let n = 64;
println!("pub const CIRCLE_{}: [Vec2; {}] = [", n, n+1);
for i in 0..=n {
let a = std::f64::consts::TAU * i as f64 / n as f64;
println!(" vec2({:.06}, {:.06}),", a.cos(), a.sin());
}
println!("];")
}
*/
// fn main() {
// let n = 64;
// println!("pub const CIRCLE_{}: [Vec2; {}] = [", n, n+1);
// for i in 0..=n {
// let a = std::f64::consts::TAU * i as f64 / n as f64;
// println!(" vec2({:.06}, {:.06}),", a.cos(), a.sin());
// }
// println!("];")
// }
use emath::{vec2, Vec2};

View File

@ -78,11 +78,15 @@ impl Default for GlyphInfo {
pub struct FontImpl {
name: String,
ab_glyph_font: ab_glyph::FontArc,
/// Maximum character height
scale_in_pixels: u32,
height_in_points: f32,
// move each character by this much (hack)
y_offset: f32,
ascent: f32,
pixels_per_point: f32,
glyph_info_cache: RwLock<ahash::HashMap<char, GlyphInfo>>, // TODO(emilk): standard Mutex
@ -320,8 +324,10 @@ type FontIndex = usize;
/// Wrapper over multiple [`FontImpl`] (e.g. a primary + fallbacks for emojis)
pub struct Font {
fonts: Vec<Arc<FontImpl>>,
/// Lazily calculated.
characters: Option<BTreeSet<char>>,
replacement_glyph: (FontIndex, GlyphInfo),
pixels_per_point: f32,
row_height: f32,

View File

@ -193,8 +193,10 @@ impl std::hash::Hash for LayoutJob {
pub struct LayoutSection {
/// Can be used for first row indentation.
pub leading_space: f32,
/// Range into the galley text
pub byte_range: Range<usize>,
pub format: TextFormat,
}
@ -218,12 +220,18 @@ impl std::hash::Hash for LayoutSection {
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub struct TextFormat {
pub font_id: FontId,
/// Text color
pub color: Color32,
pub background: Color32,
pub italics: bool,
pub underline: Stroke,
pub strikethrough: Stroke,
/// If you use a small font and [`Align::TOP`] you
/// can get the effect of raised text.
pub valign: Align,

View File

@ -9,8 +9,10 @@ use crate::{ImageData, ImageDelta, TextureId};
pub struct TextureManager {
/// We allocate texture id:s linearly.
next_id: u64,
/// Information about currently allocated textures.
metas: ahash::HashMap<TextureId, TextureMeta>,
delta: TexturesDelta,
}

132
scripts/lint.py Executable file
View File

@ -0,0 +1,132 @@
#!/usr/bin/env python
"""
Runs custom linting on Rust code.
"""
import argparse
import os
import re
import sys
def lint_file_path(filepath, args) -> int:
with open(filepath) as f:
lines_in = f.readlines()
errors, lines_out = lint_lines(filepath, lines_in)
for error in errors:
print(error)
if args.fix and lines_in != lines_out:
with open(filepath, 'w') as f:
f.writelines(lines_out)
print(f'{filepath} fixed.')
return len(errors)
def lint_lines(filepath, lines_in):
last_line_was_empty = True
errors = []
lines_out = []
for line_nr, line in enumerate(lines_in):
line_nr = line_nr+1
# TODO: only # and /// on lines before a keyword
pattern = r'^\s*((///)|((pub(\(\w*\))? )?((impl|fn|struct|enum|union|trait)\b))).*$'
if re.match(pattern, line):
if not last_line_was_empty:
errors.append(
f'{filepath}:{line_nr}: for readability, add newline before `{line.strip()}`')
lines_out.append("\n")
lines_out.append(line)
stripped = line.strip()
last_line_was_empty = stripped == '' or \
stripped.startswith('#') or \
stripped.startswith('//') or \
stripped.endswith('{') or \
stripped.endswith('(') or \
stripped.endswith('\\') or \
stripped.endswith('r"') or \
stripped.endswith(']')
return errors, lines_out
def test_lint():
should_pass = [
"hello world",
"""
/// docstring
foo
/// docstring
bar
"""
]
should_fail = [
"""
/// docstring
foo
/// docstring
bar
"""
]
for code in should_pass:
errors, _ = lint_lines("test.py", code.split('\n'))
assert len(errors) == 0, f'expected this to pass:\n{code}\ngot: {errors}'
for code in should_fail:
errors, _ = lint_lines("test.py", code.split('\n'))
assert len(errors) > 0, f'expected this to fail:\n{code}'
pass
def main():
test_lint() # Make sure we are bug free before we run!
parser = argparse.ArgumentParser(
description='Lint Rust code with custom linter.')
parser.add_argument('files', metavar='file', type=str, nargs='*',
help='File paths. Empty = all files, recursively.')
parser.add_argument('--fix', dest='fix', action='store_true',
help='Automatically fix the files')
args = parser.parse_args()
num_errors = 0
if args.files:
for filepath in args.files:
num_errors += lint_file_path(filepath, args)
else:
script_dirpath = os.path.dirname(os.path.realpath(__file__))
root_dirpath = os.path.abspath(f'{script_dirpath}/..')
os.chdir(root_dirpath)
exclude = set(['target', 'target_ra'])
for root, dirs, files in os.walk('.', topdown=True):
dirs[:] = [d for d in dirs if d not in exclude]
for filename in files:
if filename.endswith('.rs'):
filepath = os.path.join(root, filename)
num_errors += lint_file_path(filepath, args)
if num_errors == 0:
print(f"{sys.argv[0]} finished without error")
sys.exit(0)
else:
print(f"{sys.argv[0]} found {num_errors} errors.")
sys.exit(1)
if __name__ == '__main__':
main()