2022-11-26 23:57:50 +00:00
|
|
|
// Copyright 2020 The Jujutsu Authors
|
2020-12-12 08:00:42 +00:00
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// https://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
|
|
|
|
use std::hash::Hash;
|
2024-02-11 18:43:06 +00:00
|
|
|
use std::io;
|
2020-12-12 08:00:42 +00:00
|
|
|
use std::io::Write;
|
|
|
|
|
2023-01-27 06:33:24 +00:00
|
|
|
use itertools::Itertools;
|
2023-06-28 14:12:40 +00:00
|
|
|
use jj_lib::settings::UserSettings;
|
2024-08-22 18:18:15 +00:00
|
|
|
use renderdag::Ancestor;
|
|
|
|
use renderdag::GraphRowRenderer;
|
|
|
|
use renderdag::Renderer;
|
2023-01-16 13:20:42 +00:00
|
|
|
|
2020-12-12 08:00:42 +00:00
|
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
|
|
// An edge to another node in the graph
|
|
|
|
pub enum Edge<T> {
|
2024-02-17 08:37:35 +00:00
|
|
|
Direct(T),
|
|
|
|
Indirect(T),
|
2020-12-12 08:00:42 +00:00
|
|
|
Missing,
|
|
|
|
}
|
|
|
|
|
2023-01-16 13:20:42 +00:00
|
|
|
pub trait GraphLog<K: Clone + Eq + Hash> {
|
|
|
|
fn add_node(
|
|
|
|
&mut self,
|
|
|
|
id: &K,
|
|
|
|
edges: &[Edge<K>],
|
|
|
|
node_symbol: &str,
|
|
|
|
text: &str,
|
|
|
|
) -> io::Result<()>;
|
2023-03-10 07:44:34 +00:00
|
|
|
|
|
|
|
fn width(&self, id: &K, edges: &[Edge<K>]) -> usize;
|
2023-01-16 13:20:42 +00:00
|
|
|
}
|
|
|
|
|
2023-01-27 16:59:04 +00:00
|
|
|
pub struct SaplingGraphLog<'writer, R> {
|
2023-01-27 06:33:24 +00:00
|
|
|
renderer: R,
|
|
|
|
writer: &'writer mut dyn Write,
|
|
|
|
}
|
2023-01-16 13:20:42 +00:00
|
|
|
|
2023-01-27 06:33:24 +00:00
|
|
|
impl<K: Clone> From<&Edge<K>> for Ancestor<K> {
|
|
|
|
fn from(e: &Edge<K>) -> Self {
|
|
|
|
match e {
|
2024-02-17 08:37:35 +00:00
|
|
|
Edge::Direct(target) => Ancestor::Parent(target.clone()),
|
|
|
|
Edge::Indirect(target) => Ancestor::Ancestor(target.clone()),
|
2023-01-27 06:33:24 +00:00
|
|
|
Edge::Missing => Ancestor::Anonymous,
|
2023-01-16 13:20:42 +00:00
|
|
|
}
|
|
|
|
}
|
2023-01-27 06:33:24 +00:00
|
|
|
}
|
2023-01-16 13:20:42 +00:00
|
|
|
|
2023-01-27 16:59:04 +00:00
|
|
|
impl<'writer, K, R> GraphLog<K> for SaplingGraphLog<'writer, R>
|
2023-01-27 06:33:24 +00:00
|
|
|
where
|
|
|
|
K: Clone + Eq + Hash,
|
|
|
|
R: Renderer<K, Output = String>,
|
|
|
|
{
|
|
|
|
fn add_node(
|
|
|
|
&mut self,
|
|
|
|
id: &K,
|
|
|
|
edges: &[Edge<K>],
|
|
|
|
node_symbol: &str,
|
|
|
|
text: &str,
|
|
|
|
) -> io::Result<()> {
|
|
|
|
let row = self.renderer.next_row(
|
|
|
|
id.clone(),
|
|
|
|
edges.iter().map_into().collect(),
|
|
|
|
node_symbol.into(),
|
|
|
|
text.into(),
|
|
|
|
);
|
|
|
|
|
|
|
|
write!(self.writer, "{row}")
|
2023-01-16 13:20:42 +00:00
|
|
|
}
|
2023-03-10 07:44:34 +00:00
|
|
|
|
|
|
|
fn width(&self, id: &K, edges: &[Edge<K>]) -> usize {
|
|
|
|
let parents = edges.iter().map_into().collect();
|
|
|
|
let w: u64 = self.renderer.width(Some(id), Some(&parents));
|
|
|
|
w.try_into().unwrap()
|
|
|
|
}
|
2023-01-27 06:33:24 +00:00
|
|
|
}
|
2023-01-16 13:20:42 +00:00
|
|
|
|
2023-01-27 16:59:04 +00:00
|
|
|
impl<'writer, R> SaplingGraphLog<'writer, R> {
|
|
|
|
pub fn create<K>(
|
2023-01-27 06:33:24 +00:00
|
|
|
renderer: R,
|
|
|
|
formatter: &'writer mut dyn Write,
|
2023-01-27 16:59:04 +00:00
|
|
|
) -> Box<dyn GraphLog<K> + 'writer>
|
|
|
|
where
|
|
|
|
K: Clone + Eq + Hash + 'writer,
|
|
|
|
R: Renderer<K, Output = String> + 'writer,
|
|
|
|
{
|
2023-01-27 06:33:24 +00:00
|
|
|
Box::new(SaplingGraphLog {
|
|
|
|
renderer,
|
|
|
|
writer: formatter,
|
|
|
|
})
|
2023-01-16 13:20:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-09-03 07:51:06 +00:00
|
|
|
#[derive(Clone, Copy, Debug, Eq, PartialEq, serde::Deserialize)]
|
|
|
|
#[serde(rename_all(deserialize = "kebab-case"))]
|
|
|
|
pub enum GraphStyle {
|
|
|
|
Ascii,
|
|
|
|
AsciiLarge,
|
|
|
|
Curved,
|
|
|
|
Square,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl GraphStyle {
|
|
|
|
pub fn from_settings(settings: &UserSettings) -> Self {
|
|
|
|
settings
|
|
|
|
.config()
|
|
|
|
.get("ui.graph.style")
|
|
|
|
.unwrap_or(GraphStyle::Curved)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn is_ascii(self) -> bool {
|
|
|
|
match self {
|
|
|
|
GraphStyle::Ascii | GraphStyle::AsciiLarge => true,
|
|
|
|
GraphStyle::Curved | GraphStyle::Square => false,
|
|
|
|
}
|
|
|
|
}
|
2024-09-03 07:37:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn node_template_for_key(
|
|
|
|
settings: &UserSettings,
|
|
|
|
key: &str,
|
|
|
|
fallback: &str,
|
|
|
|
ascii_fallback: &str,
|
|
|
|
) -> String {
|
|
|
|
let symbol = settings.config().get_string(key);
|
2024-09-03 07:51:06 +00:00
|
|
|
if GraphStyle::from_settings(settings).is_ascii() {
|
|
|
|
symbol.unwrap_or_else(|_| ascii_fallback.to_owned())
|
|
|
|
} else {
|
|
|
|
symbol.unwrap_or_else(|_| fallback.to_owned())
|
2024-09-03 07:37:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-16 13:20:42 +00:00
|
|
|
pub fn get_graphlog<'a, K: Clone + Eq + Hash + 'a>(
|
2023-01-27 06:33:24 +00:00
|
|
|
settings: &UserSettings,
|
2023-01-16 13:20:42 +00:00
|
|
|
formatter: &'a mut dyn Write,
|
|
|
|
) -> Box<dyn GraphLog<K> + 'a> {
|
2023-01-27 06:33:24 +00:00
|
|
|
let builder = GraphRowRenderer::new().output().with_min_row_height(0);
|
2024-09-03 07:51:06 +00:00
|
|
|
match GraphStyle::from_settings(settings) {
|
|
|
|
GraphStyle::Ascii => SaplingGraphLog::create(builder.build_ascii(), formatter),
|
|
|
|
GraphStyle::AsciiLarge => SaplingGraphLog::create(builder.build_ascii_large(), formatter),
|
|
|
|
GraphStyle::Curved => SaplingGraphLog::create(builder.build_box_drawing(), formatter),
|
|
|
|
GraphStyle::Square => {
|
2024-03-11 14:18:11 +00:00
|
|
|
SaplingGraphLog::create(builder.build_box_drawing().with_square_glyphs(), formatter)
|
|
|
|
}
|
2020-12-12 08:00:42 +00:00
|
|
|
}
|
|
|
|
}
|