More basic stuff and features

This commit is contained in:
Booklordofthedings 2025-05-05 13:48:51 +02:00
parent ba98da2b17
commit 5de1d8fc07
11 changed files with 449 additions and 80 deletions

18
src/Page.bf Normal file
View file

@ -0,0 +1,18 @@
namespace Writer;
using System;
abstract class Page
{
private String _content = new .() ~ delete _;
public virtual void ComputeStyle(StringView className, String buffer)
{
}
public virtual void ComputeContent(String buffer) => buffer.Append(_content);
public void AddHeading(uint8 n, StringView content) => _content.Append(scope $"<h{n}>{content}</h{n}>");
public void AddParagraph(StringView content) => _content.Append(scope $"<div>{content}</div>");
public void AddCode(StringView code) => _content.Append(scope $"<code>{code}</code>");
}

29
src/Pages/ExamplePage.bf Normal file
View file

@ -0,0 +1,29 @@
namespace Writer;
using System;
class ExamplePage : Page
{
public this()
{
this.AddHeading(1, "Writer - documents to pdf");
this.AddParagraph("""
Write Beef code to create printable html documents and convert them into pdf files for things like essays.
""");
this.AddCode("""
using System;
class Program
{
}
""");
}
public override void ComputeStyle(System.StringView className, System.String buffer)
{
buffer.Append(scope $"""
.{className} \{
\}
""");
}
}

View file

@ -0,0 +1,62 @@
namespace Writer;
using System;
using System.Collections;
class ImageIndexPage : Page
{
private String Layerinfo = new .("") ~ delete _;
public this(params Span<TOCItem> items)
{
this.AddHeading(3, "Abbildungsverzeichnis");
for (var i in items)
AddItem(i);
}
public override void ComputeStyle(System.StringView className, System.String buffer)
{
buffer.Append(scope $"""
.{className} \{
page: image-index;
\}
.article \{
display: flex;
\}
.article .item,
.article .price \{
flex: 1 0 auto;
\}
.article .dots \{
flex: 0 1 auto;
margin: 0 5px;
/*Allows too long content to be hidden.*/
overflow: hidden;
\}
.dots::before \{
display: block;
white-space: nowrap;
overflow: hidden;
text-overflow: clip;
content:
". . . . . . . . . . . . . . . . . . . . "
". . . . . . . . . . . . . . . . . . . . "
". . . . . . . . . . . . . . . . . . . . "
". . . . . . . . . . . . . . . . . . . . "
\}
""");
}
private void AddItem(TOCItem item)
{
this.[Friend]_content.Append(scope $"""
<div class="article">
<span class="item">{item.Name}</span>
<span class="dots"></span>
<span class="price">{item.Page}</span>
</div>
""");
}
}

69
src/Pages/IndexPage.bf Normal file
View file

@ -0,0 +1,69 @@
namespace Writer;
using System;
using System.Collections;
class IndexPage : Page
{
private String Layerinfo = new .("") ~ delete _;
public this(params Span<TOCItem> items)
{
this.AddHeading(3, "Inhaltsverzeichnis");
for (var i in items)
AddItem(i, true);
}
public override void ComputeStyle(System.StringView className, System.String buffer)
{
buffer.Append(scope $"""
.{className} \{
page: index;
counter-reset: page 1;
\}
.article \{
display: flex;
\}
.article .item,
.article .price \{
flex: 1 0 auto;
\}
.article .dots \{
flex: 0 1 auto;
margin: 0 5px;
/*Allows too long content to be hidden.*/
overflow: hidden;
\}
.dots::before \{
display: block;
white-space: nowrap;
overflow: hidden;
text-overflow: clip;
content:
". . . . . . . . . . . . . . . . . . . . "
". . . . . . . . . . . . . . . . . . . . "
". . . . . . . . . . . . . . . . . . . . "
". . . . . . . . . . . . . . . . . . . . "
\}
""");
}
private void AddItem(TOCItem item, bool bold = false)
{
if (bold)
this.[Friend]_content.Append("<b>");
this.[Friend]_content.Append(scope $"""
<div class="article">
<span class="item">{item.Name}</span>
<span class="dots"></span>
<span class="price">{item.Page}</span>
</div>
""");
if (bold)
this.[Friend]_content.Append("</b>");
for (var i in item.Items)
AddItem(i);
}
}

51
src/Pages/TitlePage.bf Normal file
View file

@ -0,0 +1,51 @@
namespace Writer;
using System;
class TitlePage : Page
{
public this(StringView title, StringView prof, StringView date)
{
this.[Friend]_content.Append(scope $"""
<br><br>
Fachhochschule der Wirtschaft <br>
-FHDW- <br>
Paderborn <br>
<br><br><br>
<b>Studienarbeit</b>
<br><br><br>
Thema:<br><br>
<b style="font-size:20pt;">{title}</b>
<br><br><br>
Prüfer:<br>
prof<br>
<br><br>
Verfasser:<br>
Jannis-Leander von Hagen
<br><br>
Wirtschaftsinformatik<br>
Cyber Security<br><br>
Eingereicht am:<br>
{date}
""");
}
public override void ComputeStyle(System.StringView className, System.String buffer)
{
buffer.Append(scope $"""
.{className} \{
page: cover;
font-size:16pt;
counter-reset: page 1;
\}
""");
}
}

View file

@ -5,10 +5,52 @@ class Program
public static void Main()
{
Writer w = scope .();
w.Write(scope TitlePage("Writer - Create Documents", "Unknown", "05.05.2025"));
w.AddHeading(1, "Doing things better");
w.AddParagraph();
w.Write(scope IndexPage(
.("Inhaltsverzeichnis", "I"),
.("Abbildungsverzeichnis", "II"),
.("1 Einleitung", "1", .("1.1 Unterpunkt", "2"))
));
w.Output("index.html");
w.Write(scope ImageIndexPage(
.("<b>Abbildung 1</b> The origin of the world", "2")
));
w.Write(scope ExamplePage());
if (w.Safe("index.html") case .Ok)
w.Convert("index.html", "result.pdf").IgnoreError();
}
}
}
/*
The original usecase for this library is to serve as a tool to
create scientific texts for uni.
Some code may look a bit bad, and will continue to do so until I can clean up
and make this entire thing a bit more generic.
Requirement:
HeadingPage:
- All text centered x
- No decorations x
Roman Pages:
- Top page with title
- Roman numeral numbering
- Index, Picture Index
Normal Pages:
- Top page with title
- Arabic numerals
- Footnotes
- Numeric titles (1, 1.1, 2, 2.0)
Images:
- Subtitles
- Convert into base64 loaded image
Codeblocks:
*/

View file

@ -1,8 +0,0 @@
namespace Writer;
using System;
abstract class Section
{
public abstract void Compute(String input);
}

View file

@ -1,20 +0,0 @@
namespace Writer.Sections;
using System;
class Heading : Section
{
public uint8 Level = 1;
public String Name = new .() ~ delete _;
public this(uint8 level, StringView name)
{
Level = level;
Name.Set(name);
}
public override void Compute(String input)
{
input.Append(scope $"<h{Level}>{Name}</h{Level}>");
}
}

View file

@ -1,17 +0,0 @@
namespace Writer.Sections;
using System;
class Paragraph : Section
{
public override void Compute(System.String input)
{
String ipsum = """
Lorem ipsum dolor sit amet consectetur adipiscing elit. Semper vel class aptent taciti sociosqu ad litora. Blandit quis suspendisse aliquet nisi sodales consequat magna. Cras eleifend turpis fames primis vulputate ornare sagittis. Sem placerat in id cursus mi pretium tellus. Orci varius natoque penatibus et magnis dis parturient. Finibus facilisis dapibus etiam interdum tortor ligula congue. Proin libero feugiat tristique accumsan maecenas potenti ultricies. Sed diam urna tempor pulvinar vivamus fringilla lacus. Eros lobortis nulla molestie mattis scelerisque maximus eget. Porta elementum a enim euismod quam justo lectus. Curabitur facilisi cubilia curae hac habitasse platea dictumst. Nisl malesuada lacinia integer nunc posuere ut hendrerit. Efficitur laoreet mauris pharetra vestibulum fusce dictum risus. Imperdiet mollis nullam volutpat porttitor ullamcorper rutrum gravida. Adipiscing elit quisque faucibus ex sapien vitae pellentesque. Ad litora torquent per conubia nostra inceptos himenaeos. Consequat magna ante condimentum neque at luctus nibh. Ornare sagittis vehicula praesent dui felis venenatis ultrices. Pretium tellus duis convallis tempus leo eu aenean. Dis parturient montes nascetur ridiculus mus donec rhoncus. Ligula congue sollicitudin erat viverra ac tincidunt nam. Potenti ultricies habitant morbi senectus netus suscipit auctor. Fringilla lacus nec metus bibendum egestas iaculis massa. Maximus eget fermentum odio phasellus non purus est. Justo lectus commodo augue arcu dignissim velit aliquam. Platea dictumst lorem ipsum dolor sit amet consectetur. Ut hendrerit semper vel class aptent taciti sociosqu. Dictum risus blandit quis suspendisse aliquet nisi sodales. Rutrum gravida cras eleifend turpis fames primis vulputate. Vitae pellentesque sem placerat in id cursus mi. Inceptos himenaeos orci varius natoque penatibus et magnis. Luctus nibh finibus facilisis dapibus etiam interdum tortor. Venenatis ultrices proin libero feugiat tristique accumsan maecenas. Eu aenean sed diam urna tempor pulvinar vivamus. Donec rhoncus eros lobortis nulla molestie mattis scelerisque. Tincidunt nam porta elementum a enim euismod quam. Suscipit auctor curabitur facilisi cubilia curae hac habitasse. Iaculis massa nisl malesuada lacinia integer nunc posuere. Purus est efficitur laoreet mauris pharetra vestibulum fusce. Velit aliquam imperdiet mollis nullam volutpat porttitor ullamcorper. Amet consectetur adipiscing elit quisque faucibus ex sapien. Taciti sociosqu ad litora torquent per conubia nostra. Nisi sodales consequat magna ante condimentum neque at. Primis vulputate ornare sagittis vehicula praesent dui felis. Cursus mi pretium tellus duis convallis tempus leo. Et magnis dis parturient montes nascetur ridiculus mus. Interdum tortor ligula congue sollicitudin erat viverra ac. Accumsan maecenas potenti ultricies habitant morbi senectus netus. Pulvinar vivamus fringilla lacus nec metus bibendum egestas.
""";
input.Append(scope $"""
<p>{ipsum}</p>
""");
}
}

19
src/TOCItem.bf Normal file
View file

@ -0,0 +1,19 @@
namespace Writer;
using System;
using System.Collections;
struct TOCItem
{
public StringView Name;
public StringView Page;
public Span<TOCItem> Items;
public this(StringView name, StringView page, params Span<TOCItem> items)
{
Name = name;
Page = page;
Items = items;
}
}

View file

@ -6,60 +6,184 @@ using System.Collections;
class Writer
{
private List<Section> _sections = new .() ~ DeleteContainerAndItems!(_);
private String _title = new .() ~ delete _;
private List<Page> _pages = new .() ~ delete _;
public String Title = new .("Writer page") ~ delete _;
public String Style = new .("""
public StringView DefaultStyle = """
@page {
size:A4;
margin-left:4cm;
margin-right:2cm;
margin-top:1.27cm;
margin-bottom:2.5cm;
padding-top:0.5cm;
@top-right {
content: counter(page);
font-size:10pt;
border-bottom:1px solid black;
margin-top:1.27cm;
height:0.5cm;
}
@top-left {
font-size:10pt;
content: string(title);
border-bottom:1px solid black;
margin-top:1.27cm;
height:0.5cm;
}
@top-center {
border-bottom:1px solid black;
margin-top:1.27cm;
height:0.5cm;
}
@footnote {
float: bottom;
border-top:1px solid black;
}
}
@page cover {
text-align:center;
break-after: page;
@top-right {
content:none;
border-bottom:0px solid black;
}
@top-left {
content:none;
border-bottom:0px solid black;
}
@top-center {
border-bottom:0px solid black;
}
}
@page index {
break-after: page;
@top-right {
content: counter(page, upper-roman);
border-bottom:1px solid black;
}
@top-left {
border-bottom:1px solid black;
}
@top-center {
border-bottom:1px solid black;
}
}
@page image-index {
break-after: page;
@top-right {
content: counter(page, upper-roman);
border-bottom:1px solid black;
}
@top-left {
border-bottom:1px solid black;
}
@top-center {
border-bottom:1px solid black;
}
}
@media screen {
.web {
max-width: 60rem;
margin: 0 auto;
}
.footnote {
display:none;
}
}
body {
margin:0px;
padding:0px;
line-height:150%;
font-family:arial;
font-size:12pt;
}
h1, h2, h3, h4, h5, h6 {
border-bottom:1px solid black;
padding-bottom:5px;
h1, h2, h3 {
string-set: title content(text);
}
""") ~ delete _;
code {
display:block;
border:1px solid black;
}
.footnote {
float: footnote;
}
""";
public void Output(StringView location)
public this(StringView title = "Writer Document")
{
String sections = new .();
defer delete sections;
_title.Set(title);
}
///Add a page to hte list of pages to render
public void Write(Page page) => _pages.Add(page);
File.WriteAllText(location, scope $"""
<!DOCTYPE html>
///Output the page into a html file
public Result<void> Safe(StringView fileName = "index.html")
{
String pageContent = new .();
defer delete pageContent;
String pageStyles = new .();
defer delete pageStyles;
pageStyles.Append(DefaultStyle);
int counter = 0;
for (var p in _pages)
{
counter++;
p.ComputeStyle(scope $"class-{counter}", pageStyles);
pageContent.Append(scope $"<div class=\"class-{counter}\">{p.ComputeContent(.. scope .())}</div>");
}
String output = new .(scope $"""
<!doctype html>
<html>
<head>
<title>{Title}</title>
<style>{Style}</style>
</head>
<body>
{this._ComputeSections(.. sections)}
</footer>
</body>
<head>
<title>{_title}</title>
<style>{pageStyles}</style>
</head>
<body><div class="web">{pageContent}</div></body>
</html>
""");
defer delete output;
if (File.WriteAllText(fileName, output) case .Err)
return .Err;
return .Ok;
}
private void _ComputeSections(String buffer)
///Convert the given html file into a pdf file, assuming pagedjs-cli is installed
public Result<void> Convert(StringView inputFile, StringView fileName)
{
for (var i in _sections)
i.Compute(buffer);
System.Diagnostics.ProcessStartInfo info = scope .();
info.SetFileName("pagedjs-cli");
//This might be vulnerable
info.SetArguments(scope $"{inputFile} -o {fileName}");
System.Diagnostics.SpawnedProcess process = scope .();
if (process.Start(info) case .Ok)
{
while (!process.HasExited)
continue;
return .Ok;
}
return .Err;
}
public void AddHeading(uint8 size, StringView content) => _sections.Add(new Writer.Sections.Heading(size, content));
public void AddParagraph() => _sections.Add(new Writer.Sections.Paragraph());
}