Skip to content

Commit

Permalink
Add support for sorting the output of the generate tree command by …
Browse files Browse the repository at this point in the history
…the items' name, visibility or kind
  • Loading branch information
regexident committed Nov 14, 2023
1 parent d3a2953 commit 637095b
Show file tree
Hide file tree
Showing 9 changed files with 408 additions and 5 deletions.
4 changes: 3 additions & 1 deletion src/generate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,9 @@ impl Command {
uses: false,
externs: false,
};
let printer_options = TreePrinterOptions {};
let printer_options = TreePrinterOptions {
sort_by: options.sort_by,
};

let command =
GenerateTreeCommand::new(builder_options, filter_options, printer_options);
Expand Down
31 changes: 30 additions & 1 deletion src/item/visibility.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

use std::fmt;
use std::{cmp::Ordering, fmt};

use ra_ap_hir::{self as hir, HasVisibility};
use ra_ap_ide_db::RootDatabase;
Expand Down Expand Up @@ -48,6 +48,35 @@ impl ItemVisibility {
hir::Visibility::Public => Self::Public,
}
}

fn numerical_order(&self) -> isize {
match self {
ItemVisibility::Public => 0,
ItemVisibility::Crate => 1,
ItemVisibility::Module(_) => 2,
ItemVisibility::Super => 3,
ItemVisibility::Private => 4,
}
}
}

impl PartialOrd for ItemVisibility {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}

impl Ord for ItemVisibility {
fn cmp(&self, other: &Self) -> Ordering {
match self.numerical_order().cmp(&other.numerical_order()) {
ord @ Ordering::Less => ord,
ord @ Ordering::Equal => match (self, other) {
(ItemVisibility::Module(lhs), ItemVisibility::Module(rhs)) => lhs.cmp(rhs),
_ => ord,
},
ord @ Ordering::Greater => ord,
}
}
}

impl fmt::Display for ItemVisibility {
Expand Down
38 changes: 38 additions & 0 deletions src/tree/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,43 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

use std::str::FromStr;

use clap::{ArgAction, Parser};

use crate::options;

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum SortBy {
Name,
Visibility,
Kind,
}

impl FromStr for SortBy {
type Err = &'static str;

fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"name" => Ok(Self::Name),
"visibility" => Ok(Self::Visibility),
"kind" => Ok(Self::Kind),
_ => Err("Unrecognized sort order"),
}
}
}

impl ToString for SortBy {
fn to_string(&self) -> String {
match self {
Self::Name => "name",
Self::Visibility => "visibility",
Self::Kind => "kind",
}
.to_owned()
}
}

#[derive(Parser, Clone, PartialEq, Eq, Debug)]
#[group(id = "GenerateTreeOptions")]
pub struct Options {
Expand All @@ -18,6 +51,11 @@ pub struct Options {
#[command(flatten)]
pub selection: options::selection::Options,

/// The sorting order to use
/// (e.g. name, visibility, kind).
#[arg(long = "sort-by", default_value = "name")]
pub sort_by: SortBy,

/// Include orphaned modules (i.e. unused files in /src).
#[arg(long = "orphans")]
pub orphans: bool,
Expand Down
2 changes: 2 additions & 0 deletions src/tree/orphans.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ fn orphan_node(crate_name: Option<String>, path: Vec<String>, file_path: PathBuf
let test = None;
ItemAttrs { cfgs, test }
};
let kind = None;

let item = Item {
crate_name,
Expand All @@ -93,6 +94,7 @@ fn orphan_node(crate_name: Option<String>, path: Vec<String>, file_path: PathBuf
hir,
visibility,
attrs,
kind,
};

Node::new(item, vec![])
Expand Down
24 changes: 21 additions & 3 deletions src/tree/printer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use yansi::Style;
use crate::{
item::visibility::ItemVisibility,
theme::tree::styles,
tree::{node::Node, Tree},
tree::{node::Node, options::SortBy, Tree},
};

#[derive(Debug)]
Expand All @@ -21,7 +21,9 @@ struct Twig {
}

#[derive(Clone, Debug)]
pub struct Options {}
pub struct Options {
pub sort_by: SortBy,
}

pub struct Printer<'a> {
#[allow(dead_code)]
Expand Down Expand Up @@ -52,7 +54,23 @@ impl<'a> Printer<'a> {
let mut subnodes = root_node.subnodes.clone();

// Sort the children by name for easier visual scanning of output:
subnodes.sort_by_cached_key(|node| node.display_name());
subnodes.sort_by_cached_key(|node| node.item.display_name());

// The default sorting functions in Rust are stable, so we can use it to re-sort,
// resulting in a list that's sorted prioritizing whatever we re-sort by.

// Re-sort the children by name, visibility or kind, for easier visual scanning of output:
match self.options.sort_by {
SortBy::Name => {
subnodes.sort_by_cached_key(|node| node.item.display_name());
}
SortBy::Visibility => {
subnodes.sort_by_cached_key(|node| node.item.visibility.clone());
}
SortBy::Kind => {
subnodes.sort_by_cached_key(|node| node.item.kind.clone());
}
}

let count = subnodes.len();
for (pos, node) in subnodes.into_iter().enumerate() {
Expand Down
41 changes: 41 additions & 0 deletions tests/generate_tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -414,3 +414,44 @@ mod max_depth {
);
}
}

mod sort_by {
mod name {
test_cmd!(
args: "generate tree \
--types \
--traits \
--fns \
--sort-by \"name\"",
success: true,
color_mode: ColorMode::Plain,
project: smoke
);
}

mod visibility {
test_cmd!(
args: "generate tree \
--types \
--traits \
--fns \
--sort-by \"visibility\"",
success: true,
color_mode: ColorMode::Plain,
project: smoke
);
}

mod kind {
test_cmd!(
args: "generate tree \
--types \
--traits \
--fns \
--sort-by \"kind\"",
success: true,
color_mode: ColorMode::Plain,
project: smoke
);
}
}
91 changes: 91 additions & 0 deletions tests/snapshots/generate_tree__sort_by__kind__smoke.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
---
source: tests/generate_tree.rs
expression: output
---
STDERR:

STDOUT:

crate smoke
├── mod hierarchy: pub(crate)
│ └── mod lorem: pub(self)
│ ├── mod consectetur: pub(self)
│ │ ├── mod adipiscing: pub(self)
│ │ │ ├── mod elit: pub(self)
│ │ │ │ └── struct Elit: pub(self)
│ │ │ └── struct Adipiscing: pub(self)
│ │ └── struct Consectetur: pub(self)
│ ├── mod dolor: pub(self)
│ │ ├── mod sit: pub(self)
│ │ │ ├── mod amet: pub(self)
│ │ │ │ └── struct Amet: pub(self)
│ │ │ └── struct Sit: pub(self)
│ │ └── struct Dolor: pub(self)
│ ├── mod ipsum: pub(self)
│ │ └── struct Ipsum: pub(self)
│ └── struct Lorem: pub(self)
├── mod orphans: pub(crate)
├── mod uses: pub(crate)
│ └── mod cycle: pub(self)
│ ├── mod node_0: pub(self)
│ └── mod node_1: pub(self)
│ └── mod node_2: pub(self)
└── mod visibility: pub(crate)
└── mod dummy: pub(self)
├── mod enums: pub(self)
│ ├── enum PubCrate: pub(crate)
│ ├── enum PubModule: pub(in crate::visibility)
│ ├── enum PubPrivate: pub(self)
│ ├── enum PubPublic: pub
│ └── enum PubSuper: pub(super)
├── mod fns: pub(self)
│ ├── fn pub_crate: pub(crate)
│ ├── fn pub_module: pub(in crate::visibility)
│ ├── fn pub_private: pub(self)
│ ├── fn pub_public: pub
│ └── fn pub_super: pub(super)
├── mod kinds: pub(self)
│ ├── mod Module: pub(self)
│ ├── unsafe trait UnsafeTrait: pub(self)
│ ├── trait Trait: pub(self)
│ ├── type TraitAlias: pub(self)
│ ├── type TypeAlias: pub(self)
│ ├── struct Struct: pub(self)
│ ├── enum Enum: pub(self)
│ ├── union Union: pub(self)
│ ├── const fn ConstFunction: pub(self)
│ ├── async fn AsyncFunction: pub(self)
│ ├── unsafe fn UnsafeFunction: pub(self)
│ └── fn Function: pub(self)
├── mod mods: pub(self)
│ ├── mod pub_crate: pub(crate)
│ ├── mod pub_module: pub(in crate::visibility)
│ ├── mod pub_private: pub(self)
│ ├── mod pub_public: pub
│ └── mod pub_super: pub(super)
├── mod structs: pub(self)
│ ├── struct PubCrate: pub(crate)
│ ├── struct PubModule: pub(in crate::visibility)
│ ├── struct PubPrivate: pub(self)
│ ├── struct PubPublic: pub
│ └── struct PubSuper: pub(super)
├── mod traits: pub(self)
│ ├── mod r#unsafe: pub(self)
│ │ ├── unsafe trait PubCrate: pub(crate)
│ │ ├── unsafe trait PubModule: pub(in crate::visibility)
│ │ ├── unsafe trait PubPrivate: pub(self)
│ │ ├── unsafe trait PubPublic: pub
│ │ └── unsafe trait PubSuper: pub(super)
│ └── mod safe: pub(self)
│ ├── trait PubCrate: pub(crate)
│ ├── trait PubModule: pub(in crate::visibility)
│ ├── trait PubPrivate: pub(self)
│ ├── trait PubPublic: pub
│ └── trait PubSuper: pub(super)
└── mod unions: pub(self)
├── union PubCrate: pub(crate)
├── union PubModule: pub(in crate::visibility)
├── union PubPrivate: pub(self)
├── union PubPublic: pub
└── union PubSuper: pub(super)

Loading

0 comments on commit 637095b

Please sign in to comment.