Compare commits
10 Commits
v0.0.1
...
cb5838345e
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cb5838345e | ||
|
|
1107a653cf | ||
|
|
95d4ee7080 | ||
|
|
fa2dd96f78 | ||
|
|
7741e192f5 | ||
|
|
5dfd46852f | ||
|
|
88e10010d8 | ||
|
|
52c564d4fd | ||
|
|
f7874c1843 | ||
|
|
40120667f7 |
3
.dockerignore
Normal file
3
.dockerignore
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
**/.git
|
||||||
|
target/
|
||||||
|
org_test_documents/
|
||||||
151
.lighthouse/pipeline-build-natter.yaml
Normal file
151
.lighthouse/pipeline-build-natter.yaml
Normal file
@@ -0,0 +1,151 @@
|
|||||||
|
apiVersion: tekton.dev/v1beta1
|
||||||
|
kind: PipelineRun
|
||||||
|
metadata:
|
||||||
|
name: build-natter
|
||||||
|
spec:
|
||||||
|
pipelineSpec:
|
||||||
|
params:
|
||||||
|
- name: image-name
|
||||||
|
description: The name for the built image
|
||||||
|
type: string
|
||||||
|
- name: path-to-image-context
|
||||||
|
description: The path to the build context
|
||||||
|
type: string
|
||||||
|
- name: path-to-dockerfile
|
||||||
|
description: The path to the Dockerfile
|
||||||
|
type: string
|
||||||
|
tasks:
|
||||||
|
- name: report-pending
|
||||||
|
taskRef:
|
||||||
|
name: gitea-set-status
|
||||||
|
runAfter:
|
||||||
|
- fetch-repository
|
||||||
|
params:
|
||||||
|
- name: CONTEXT
|
||||||
|
value: "$(params.JOB_NAME)"
|
||||||
|
- name: REPO_FULL_NAME
|
||||||
|
value: "$(params.REPO_OWNER)/$(params.REPO_NAME)"
|
||||||
|
- name: GITEA_HOST_URL
|
||||||
|
value: code.fizz.buzz
|
||||||
|
- name: SHA
|
||||||
|
value: "$(tasks.fetch-repository.results.commit)"
|
||||||
|
- name: DESCRIPTION
|
||||||
|
value: "Build $(params.JOB_NAME) has started"
|
||||||
|
- name: STATE
|
||||||
|
value: pending
|
||||||
|
- name: TARGET_URL
|
||||||
|
value: "https://tekton.fizz.buzz/#/namespaces/$(context.pipelineRun.namespace)/pipelineruns/$(context.pipelineRun.name)"
|
||||||
|
- name: fetch-repository
|
||||||
|
taskRef:
|
||||||
|
name: git-clone
|
||||||
|
workspaces:
|
||||||
|
- name: output
|
||||||
|
workspace: git-source
|
||||||
|
params:
|
||||||
|
- name: url
|
||||||
|
value: $(params.REPO_URL)
|
||||||
|
- name: revision
|
||||||
|
value: $(params.PULL_BASE_SHA)
|
||||||
|
- name: deleteExisting
|
||||||
|
value: "true"
|
||||||
|
- name: build-image-runner
|
||||||
|
taskRef:
|
||||||
|
name: kaniko
|
||||||
|
params:
|
||||||
|
- name: IMAGE
|
||||||
|
value: "$(params.image-name):$(tasks.fetch-repository.results.commit)"
|
||||||
|
- name: CONTEXT
|
||||||
|
value: $(params.path-to-image-context)
|
||||||
|
- name: DOCKERFILE
|
||||||
|
value: $(params.path-to-dockerfile)
|
||||||
|
- name: BUILDER_IMAGE
|
||||||
|
value: "gcr.io/kaniko-project/executor:v1.12.1"
|
||||||
|
- name: EXTRA_ARGS
|
||||||
|
value:
|
||||||
|
- "--destination=$(params.image-name)" # Also write the :latest image
|
||||||
|
- --cache=true
|
||||||
|
- --cache-copy-layers
|
||||||
|
- --cache-repo=harbor.fizz.buzz/kanikocache/cache
|
||||||
|
- --use-new-run # Should result in a speed-up
|
||||||
|
- --reproducible # To remove timestamps so layer caching works.
|
||||||
|
- --snapshot-mode=redo
|
||||||
|
- --skip-unused-stages=true
|
||||||
|
- --registry-mirror=dockerhub.dockerhub.svc.cluster.local
|
||||||
|
workspaces:
|
||||||
|
- name: source
|
||||||
|
workspace: git-source
|
||||||
|
- name: dockerconfig
|
||||||
|
workspace: docker-credentials
|
||||||
|
runAfter:
|
||||||
|
- fetch-repository
|
||||||
|
finally:
|
||||||
|
- name: report-success
|
||||||
|
when:
|
||||||
|
- input: "$(tasks.status)"
|
||||||
|
operator: in
|
||||||
|
values: ["Succeeded", "Completed"]
|
||||||
|
taskRef:
|
||||||
|
name: gitea-set-status
|
||||||
|
params:
|
||||||
|
- name: CONTEXT
|
||||||
|
value: "$(params.JOB_NAME)"
|
||||||
|
- name: REPO_FULL_NAME
|
||||||
|
value: "$(params.REPO_OWNER)/$(params.REPO_NAME)"
|
||||||
|
- name: GITEA_HOST_URL
|
||||||
|
value: code.fizz.buzz
|
||||||
|
- name: SHA
|
||||||
|
value: "$(tasks.fetch-repository.results.commit)"
|
||||||
|
- name: DESCRIPTION
|
||||||
|
value: "Build $(params.JOB_NAME) has succeeded"
|
||||||
|
- name: STATE
|
||||||
|
value: success
|
||||||
|
- name: TARGET_URL
|
||||||
|
value: "https://tekton.fizz.buzz/#/namespaces/$(context.pipelineRun.namespace)/pipelineruns/$(context.pipelineRun.name)"
|
||||||
|
- name: report-failure
|
||||||
|
when:
|
||||||
|
- input: "$(tasks.status)"
|
||||||
|
operator: in
|
||||||
|
values: ["Failed"]
|
||||||
|
taskRef:
|
||||||
|
name: gitea-set-status
|
||||||
|
params:
|
||||||
|
- name: CONTEXT
|
||||||
|
value: "$(params.JOB_NAME)"
|
||||||
|
- name: REPO_FULL_NAME
|
||||||
|
value: "$(params.REPO_OWNER)/$(params.REPO_NAME)"
|
||||||
|
- name: GITEA_HOST_URL
|
||||||
|
value: code.fizz.buzz
|
||||||
|
- name: SHA
|
||||||
|
value: "$(tasks.fetch-repository.results.commit)"
|
||||||
|
- name: DESCRIPTION
|
||||||
|
value: "Build $(params.JOB_NAME) has failed"
|
||||||
|
- name: STATE
|
||||||
|
value: failure
|
||||||
|
- name: TARGET_URL
|
||||||
|
value: "https://tekton.fizz.buzz/#/namespaces/$(context.pipelineRun.namespace)/pipelineruns/$(context.pipelineRun.name)"
|
||||||
|
workspaces:
|
||||||
|
- name: git-source
|
||||||
|
- name: docker-credentials
|
||||||
|
workspaces:
|
||||||
|
- name: git-source
|
||||||
|
volumeClaimTemplate:
|
||||||
|
spec:
|
||||||
|
storageClassName: "nfs-client"
|
||||||
|
accessModes:
|
||||||
|
- ReadWriteOnce
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: 10Gi
|
||||||
|
subPath: rust-source
|
||||||
|
- name: docker-credentials
|
||||||
|
secret:
|
||||||
|
secretName: harbor-plain
|
||||||
|
serviceAccountName: build-bot
|
||||||
|
timeout: 240h0m0s
|
||||||
|
params:
|
||||||
|
- name: image-name
|
||||||
|
value: "harbor.fizz.buzz/private/natter"
|
||||||
|
- name: path-to-image-context
|
||||||
|
value: .
|
||||||
|
- name: path-to-dockerfile
|
||||||
|
value: docker/natter/Dockerfile
|
||||||
11
.lighthouse/triggers.yaml
Normal file
11
.lighthouse/triggers.yaml
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
apiVersion: config.lighthouse.jenkins-x.io/v1alpha1
|
||||||
|
kind: TriggerConfig
|
||||||
|
spec:
|
||||||
|
postsubmits:
|
||||||
|
- name: build-natter
|
||||||
|
source: "pipeline-build-natter.yaml"
|
||||||
|
# Override https-based url from lighthouse events.
|
||||||
|
clone_uri: "git@code.fizz.buzz:talexander/natter.git"
|
||||||
|
branches:
|
||||||
|
- ^main$
|
||||||
|
- ^master$
|
||||||
@@ -32,3 +32,9 @@ serde_json = "1.0.107"
|
|||||||
tokio = { version = "1.30.0", default-features = false, features = ["rt", "rt-multi-thread", "fs", "io-util"] }
|
tokio = { version = "1.30.0", default-features = false, features = ["rt", "rt-multi-thread", "fs", "io-util"] }
|
||||||
toml = "0.8.2"
|
toml = "0.8.2"
|
||||||
walkdir = "2.4.0"
|
walkdir = "2.4.0"
|
||||||
|
|
||||||
|
# Optimized build for any sort of release.
|
||||||
|
[profile.release-lto]
|
||||||
|
inherits = "release"
|
||||||
|
lto = true
|
||||||
|
strip = "symbols"
|
||||||
|
|||||||
@@ -14,6 +14,10 @@
|
|||||||
--src-block-language-background: #84828f;
|
--src-block-language-background: #84828f;
|
||||||
|
|
||||||
--quote-block-border-color: #84828f;
|
--quote-block-border-color: #84828f;
|
||||||
|
|
||||||
|
--table-border-color: #6a687a;
|
||||||
|
--table-odd-background-color: #0a0a0a;
|
||||||
|
--table-even-background-color: #141414;
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
@@ -184,4 +188,37 @@ body {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.org_table {
|
||||||
|
table-layout: fixed;
|
||||||
|
border-collapse: collapse;
|
||||||
|
border: 1px solid var(--table-border-color);
|
||||||
|
> tbody {
|
||||||
|
border-width: 1px 0;
|
||||||
|
border-style: solid;
|
||||||
|
border-color: var(--table-border-color);
|
||||||
|
> tr {
|
||||||
|
> td {
|
||||||
|
padding: 0.2rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
> tr:nth-child(odd) {
|
||||||
|
background-color: var(--table-odd-background-color);
|
||||||
|
}
|
||||||
|
> tr:nth-child(even) {
|
||||||
|
background-color: var(--table-even-background-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
> thead {
|
||||||
|
border-width: 1px 0;
|
||||||
|
border-style: solid;
|
||||||
|
border-color: var(--table-border-color);
|
||||||
|
> tr {
|
||||||
|
> th {
|
||||||
|
padding: 0.2rem;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1 +1,5 @@
|
|||||||
<table>{#.children}{>table_row/}{/.children}</table>
|
<table class="org_table">{#.children}{@select key=.type}
|
||||||
|
{@eq value="head"}{>table_head/}{/eq}
|
||||||
|
{@eq value="body"}{>table_body/}{/eq}
|
||||||
|
{@none}{!TODO: make this panic!}ERROR: Unrecognized type {.type}.{/none}
|
||||||
|
{/select}{/.children}</table>
|
||||||
|
|||||||
1
default_environment/templates/html/table_body.dust
Normal file
1
default_environment/templates/html/table_body.dust
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<tbody>{#.children}{>table_row/}{/.children}</tbody>
|
||||||
1
default_environment/templates/html/table_head.dust
Normal file
1
default_environment/templates/html/table_head.dust
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<thead>{#.children}{>table_head_row/}{/.children}</thead>
|
||||||
1
default_environment/templates/html/table_head_cell.dust
Normal file
1
default_environment/templates/html/table_head_cell.dust
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<th scope="col">{#.children}{>object/}{/.children}</th>
|
||||||
1
default_environment/templates/html/table_head_row.dust
Normal file
1
default_environment/templates/html/table_head_row.dust
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<tr>{#.children}{>table_head_cell/}{/.children}</tr>
|
||||||
13
docker/natter/Dockerfile
Normal file
13
docker/natter/Dockerfile
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
FROM rustlang/rust:nightly-alpine3.17 AS builder
|
||||||
|
|
||||||
|
RUN apk add --no-cache musl-dev
|
||||||
|
|
||||||
|
RUN mkdir /root/natter
|
||||||
|
WORKDIR /root/natter
|
||||||
|
COPY . .
|
||||||
|
# TODO: Add static build, which currently errors due to proc_macro. RUSTFLAGS="-C target-feature=+crt-static"
|
||||||
|
RUN CARGO_TARGET_DIR=/target cargo build --profile release-lto
|
||||||
|
|
||||||
|
FROM alpine:3.17 AS runner
|
||||||
|
|
||||||
|
COPY --from=builder /target/release-lto/natter /usr/bin/
|
||||||
32
docker/natter/Makefile
Normal file
32
docker/natter/Makefile
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
SHELL := bash
|
||||||
|
.ONESHELL:
|
||||||
|
.SHELLFLAGS := -eu -o pipefail -c
|
||||||
|
.DELETE_ON_ERROR:
|
||||||
|
MAKEFLAGS += --warn-undefined-variables
|
||||||
|
MAKEFLAGS += --no-builtin-rules
|
||||||
|
OS:=$(shell uname -s)
|
||||||
|
|
||||||
|
ifeq ($(origin .RECIPEPREFIX), undefined)
|
||||||
|
$(error This Make does not support .RECIPEPREFIX. Please use GNU Make 4.0 or later)
|
||||||
|
endif
|
||||||
|
.RECIPEPREFIX = >
|
||||||
|
|
||||||
|
IMAGE_NAME:=natter
|
||||||
|
TARGET :=
|
||||||
|
|
||||||
|
.PHONY: help
|
||||||
|
help:
|
||||||
|
> @grep -h "##" $(MAKEFILE_LIST) | grep -v grep | sed -E 's/^([^:]*): *## */\1: /'
|
||||||
|
|
||||||
|
.PHONY: build
|
||||||
|
build: ## Build the docker image.
|
||||||
|
> docker build --tag $(IMAGE_NAME) --target=$(TARGET) --file Dockerfile ../../
|
||||||
|
|
||||||
|
.PHONY: shell
|
||||||
|
shell: ## Launch an interactive shell inside the docker image.
|
||||||
|
shell: build
|
||||||
|
> docker run --rm -i -t --entrypoint /bin/sh --mount type=tmpfs,destination=/tmp $(IMAGE_NAME)
|
||||||
|
|
||||||
|
.PHONY: clean
|
||||||
|
clean:
|
||||||
|
> docker rmi $(IMAGE_NAME)
|
||||||
@@ -59,6 +59,7 @@ mod subscript;
|
|||||||
mod superscript;
|
mod superscript;
|
||||||
mod table;
|
mod table;
|
||||||
mod table_cell;
|
mod table_cell;
|
||||||
|
mod table_group;
|
||||||
mod table_row;
|
mod table_row;
|
||||||
mod target;
|
mod target;
|
||||||
mod timestamp;
|
mod timestamp;
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use super::render_context::RenderContext;
|
use super::render_context::RenderContext;
|
||||||
|
use super::table_group::RenderTableGroup;
|
||||||
use crate::error::CustomError;
|
use crate::error::CustomError;
|
||||||
use crate::intermediate::ITable;
|
use crate::intermediate::ITable;
|
||||||
|
use crate::intermediate::ITableGroup;
|
||||||
|
|
||||||
use super::macros::render;
|
use super::macros::render;
|
||||||
use super::table_row::RenderTableRow;
|
use super::table_row::RenderTableRow;
|
||||||
@@ -11,15 +13,29 @@ use super::table_row::RenderTableRow;
|
|||||||
#[serde(tag = "type")]
|
#[serde(tag = "type")]
|
||||||
#[serde(rename = "table")]
|
#[serde(rename = "table")]
|
||||||
pub(crate) struct RenderTable {
|
pub(crate) struct RenderTable {
|
||||||
children: Vec<RenderTableRow>,
|
children: Vec<RenderTableGroup>,
|
||||||
post_blank: organic::types::PostBlank,
|
post_blank: organic::types::PostBlank,
|
||||||
}
|
}
|
||||||
|
|
||||||
render!(RenderTable, ITable, original, render_context, {
|
render!(RenderTable, ITable, original, render_context, {
|
||||||
let children = {
|
let children = {
|
||||||
let mut ret = Vec::new();
|
let mut ret = Vec::new();
|
||||||
for obj in original.children.iter() {
|
for group in original.children.iter() {
|
||||||
ret.push(RenderTableRow::new(render_context.clone(), obj)?);
|
let mut rows = Vec::new();
|
||||||
|
match group {
|
||||||
|
ITableGroup::Head(irows) => {
|
||||||
|
for obj in irows {
|
||||||
|
rows.push(RenderTableRow::new(render_context.clone(), obj)?);
|
||||||
|
}
|
||||||
|
ret.push(RenderTableGroup::Head { children: rows });
|
||||||
|
}
|
||||||
|
ITableGroup::Body(irows) => {
|
||||||
|
for obj in irows {
|
||||||
|
rows.push(RenderTableRow::new(render_context.clone(), obj)?);
|
||||||
|
}
|
||||||
|
ret.push(RenderTableGroup::Body { children: rows });
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ret
|
ret
|
||||||
};
|
};
|
||||||
|
|||||||
12
src/context/table_group.rs
Normal file
12
src/context/table_group.rs
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
use super::table_row::RenderTableRow;
|
||||||
|
use serde::Serialize;
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize)]
|
||||||
|
#[serde(tag = "type")]
|
||||||
|
pub(crate) enum RenderTableGroup {
|
||||||
|
#[serde(rename = "head")]
|
||||||
|
Head { children: Vec<RenderTableRow> },
|
||||||
|
|
||||||
|
#[serde(rename = "body")]
|
||||||
|
Body { children: Vec<RenderTableRow> },
|
||||||
|
}
|
||||||
@@ -59,6 +59,7 @@ mod subscript;
|
|||||||
mod superscript;
|
mod superscript;
|
||||||
mod table;
|
mod table;
|
||||||
mod table_cell;
|
mod table_cell;
|
||||||
|
mod table_group;
|
||||||
mod table_row;
|
mod table_row;
|
||||||
mod target;
|
mod target;
|
||||||
mod timestamp;
|
mod timestamp;
|
||||||
@@ -126,6 +127,7 @@ pub(crate) use subscript::ISubscript;
|
|||||||
pub(crate) use superscript::ISuperscript;
|
pub(crate) use superscript::ISuperscript;
|
||||||
pub(crate) use table::ITable;
|
pub(crate) use table::ITable;
|
||||||
pub(crate) use table_cell::ITableCell;
|
pub(crate) use table_cell::ITableCell;
|
||||||
|
pub(crate) use table_group::ITableGroup;
|
||||||
pub(crate) use table_row::ITableRow;
|
pub(crate) use table_row::ITableRow;
|
||||||
pub(crate) use target::ITarget;
|
pub(crate) use target::ITarget;
|
||||||
pub(crate) use timestamp::ITimestamp;
|
pub(crate) use timestamp::ITimestamp;
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
use super::macros::intermediate;
|
use super::macros::intermediate;
|
||||||
use super::table_row::ITableRow;
|
use super::table_row::ITableRow;
|
||||||
use crate::error::CustomError;
|
use crate::error::CustomError;
|
||||||
|
use crate::intermediate::table_group::ITableGroup;
|
||||||
use organic::types::StandardProperties;
|
use organic::types::StandardProperties;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub(crate) struct ITable {
|
pub(crate) struct ITable {
|
||||||
pub(crate) children: Vec<ITableRow>,
|
pub(crate) children: Vec<ITableGroup>,
|
||||||
pub(crate) post_blank: organic::types::PostBlank,
|
pub(crate) post_blank: organic::types::PostBlank,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -15,10 +16,40 @@ intermediate!(
|
|||||||
original,
|
original,
|
||||||
intermediate_context,
|
intermediate_context,
|
||||||
{
|
{
|
||||||
let children = {
|
// Separate groups by lines, multiple contiguous lines are the same as one.
|
||||||
|
// If there is only one group, it is a tbody.
|
||||||
|
// If there are more than one group, the first is thead and the rest are tbody.
|
||||||
|
|
||||||
|
let sections = group_into_sections(&original.children);
|
||||||
|
|
||||||
|
let children = if sections.len() == 1 {
|
||||||
|
// If there is only one section, then it is a body.
|
||||||
let mut ret = Vec::new();
|
let mut ret = Vec::new();
|
||||||
for obj in original.children.iter() {
|
for group in sections.into_iter() {
|
||||||
ret.push(ITableRow::new(intermediate_context.clone(), obj).await?);
|
let mut rows = Vec::new();
|
||||||
|
for obj in group.into_iter() {
|
||||||
|
rows.push(ITableRow::new(intermediate_context.clone(), obj).await?)
|
||||||
|
}
|
||||||
|
ret.push(ITableGroup::Body(rows));
|
||||||
|
}
|
||||||
|
ret
|
||||||
|
} else {
|
||||||
|
// If there are more than one section, the first is a head and the rest are body.
|
||||||
|
let mut ret = Vec::new();
|
||||||
|
let mut sections = sections.into_iter();
|
||||||
|
if let Some(group) = sections.next() {
|
||||||
|
let mut rows = Vec::new();
|
||||||
|
for obj in group.into_iter() {
|
||||||
|
rows.push(ITableRow::new(intermediate_context.clone(), obj).await?)
|
||||||
|
}
|
||||||
|
ret.push(ITableGroup::Head(rows));
|
||||||
|
}
|
||||||
|
for group in sections {
|
||||||
|
let mut rows = Vec::new();
|
||||||
|
for obj in group.into_iter() {
|
||||||
|
rows.push(ITableRow::new(intermediate_context.clone(), obj).await?)
|
||||||
|
}
|
||||||
|
ret.push(ITableGroup::Body(rows));
|
||||||
}
|
}
|
||||||
ret
|
ret
|
||||||
};
|
};
|
||||||
@@ -29,3 +60,41 @@ intermediate!(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
enum GroupIntoSectionsState<'orig, 'parse> {
|
||||||
|
NonSection,
|
||||||
|
Section(Vec<&'orig organic::types::TableRow<'parse>>),
|
||||||
|
}
|
||||||
|
|
||||||
|
fn group_into_sections<'orig, 'parse>(
|
||||||
|
rows: &'orig Vec<organic::types::TableRow<'parse>>,
|
||||||
|
) -> Vec<Vec<&'orig organic::types::TableRow<'parse>>> {
|
||||||
|
let mut sections = Vec::new();
|
||||||
|
let mut rows = rows.into_iter();
|
||||||
|
let mut state = GroupIntoSectionsState::NonSection;
|
||||||
|
loop {
|
||||||
|
state = match (state, rows.next()) {
|
||||||
|
(GroupIntoSectionsState::NonSection, None) => break,
|
||||||
|
(GroupIntoSectionsState::NonSection, Some(row)) if row.children.is_empty() => {
|
||||||
|
GroupIntoSectionsState::NonSection
|
||||||
|
}
|
||||||
|
(GroupIntoSectionsState::NonSection, Some(row)) => {
|
||||||
|
GroupIntoSectionsState::Section(vec![row])
|
||||||
|
}
|
||||||
|
(GroupIntoSectionsState::Section(section), None) => {
|
||||||
|
sections.push(section);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
(GroupIntoSectionsState::Section(section), Some(row)) if row.children.is_empty() => {
|
||||||
|
sections.push(section);
|
||||||
|
GroupIntoSectionsState::NonSection
|
||||||
|
}
|
||||||
|
(GroupIntoSectionsState::Section(mut section), Some(row)) => {
|
||||||
|
section.push(row);
|
||||||
|
GroupIntoSectionsState::Section(section)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sections
|
||||||
|
}
|
||||||
|
|||||||
7
src/intermediate/table_group.rs
Normal file
7
src/intermediate/table_group.rs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
use super::ITableRow;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub(crate) enum ITableGroup {
|
||||||
|
Head(Vec<ITableRow>),
|
||||||
|
Body(Vec<ITableRow>),
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user