Skip to content

Commit

Permalink
Commit all the things
Browse files Browse the repository at this point in the history
  • Loading branch information
thblt committed Nov 5, 2021
1 parent aeba775 commit ddcd495
Show file tree
Hide file tree
Showing 12 changed files with 397 additions and 106 deletions.
6 changes: 2 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,12 @@ name = "tkacz"
version = "0.1.0"
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[lib]
name = "tkacz"
path = "src/lib.rs"

[[bin]]
name = "tkacz"
path = "src/cli.rs"

[dependencies]
clap = "3.0.0-beta.5"
dirs = "4.0.0"
2 changes: 0 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,3 @@ providing suggestions or feedback.
People interested in the project may begin by reading the [design
document](doc/design.org), which is (perpetually) obsolete but may
give a good idea of what Tkacz should be.

[![](https://badges.gitter.im/thblt/tkacz.svg)](https://gitter.im/thblt/tkacz?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
11 changes: 5 additions & 6 deletions elisp/tkacz.el
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@

;;;; Side views

(defun tkacz-side-view (buffer side action &optional noswap)
(defun tkacz-side-view (buffer side &optional action noswap)
"Control the display of BUFFER as a side view on SIDE.
BUFFER is a buffer, or nil.
Expand All @@ -109,14 +109,13 @@ ACTION can be:
By default, this will replace an existing side buffer, unless
NOSWAP is non-nil."
)
;; Notes to self:
;; (display-buffer-in-side-window (get-buffer-create "*TZ collections*") '((side . top)))
;; (display-buffer-in-side-window (get-buffer-create "*TZ Notes*") '((side . right)))
;; (display-buffer-in-side-window (get-buffer-create "*TZ Details*") '((side . bottom)))

;;;;; Customizations

(provide 'tkacz)

;;; tkacz.el ends here

;; Notes to self:
;; (display-buffer-in-side-window (get-buffer-create "*TZ collections*") '((side . top)))
;; (display-buffer-in-side-window (get-buffer-create "*TZ Notes*") '((side . right)))
;; (display-buffer-in-side-window (get-buffer-create "*TZ Details*") '((side . bottom)))
66 changes: 0 additions & 66 deletions src/cli.rs

This file was deleted.

Empty file added src/config.rs
Empty file.
43 changes: 15 additions & 28 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,32 +1,19 @@
type Id = i64;
//! Tkacz, a library
// * Type
pub mod config;
pub mod query;
pub mod store;
pub mod taxonomy;
pub mod thing;
pub mod types;

trait Type {
fn type_id(self) -> Id;
fn read_data (self) -> ();
}
pub use crate::query::{Query, QueryParser};
pub use crate::store::Store;
pub use crate::taxonomy::{ContentSource, Taxon};
pub use crate::thing::Thing;
pub use crate::types::{Class, Named, NamedType, NamedValue, Object, Type, Value};

trait Link {
pub const VERSION: &'static str = env!("CARGO_PKG_VERSION");

}

// ** The Book type

struct Book {

}

// * Thing

pub struct Thing {
id: Id,
pub name: String,
typ: dyn Type,
}

// * Store

pub struct Store {
things: ()
}
pub type Id = i64;
pub const TKACZ_DIR_NAME: &str = "tkacz";
11 changes: 11 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
use std::path::Path;

use tkacz::*;

fn main() {
println!("This is Tkacz {}!", tkacz::VERSION);
match Store::init(Path::new("/home/thblt/.tkcz")) {
Ok(_) => println!("Got a store"),
Err(e) => println!("Cannot create store: {}", e),
};
}
93 changes: 93 additions & 0 deletions src/query.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
use crate::store::Store;
use crate::thing::Thing;

// * The Query trait

/// A Query provides a function that determines if a thing should be
/// selected or not.
pub trait Query<'a> {
/// Return a filter that can be used to filter an iterator over
/// the Store's entities.
fn matches(&self, store: &Store, thing: &'_ Thing) -> bool;
}

// ** Booleans

// *** Not

pub struct NotQuery<'a> {
other: dyn Query<'a>,
}

impl<'a> Query<'a> for NotQuery<'a> {
fn matches(&self, store: &Store, thing: &'_ Thing) -> bool {
!self.other.matches(store, thing)
}
}

// *** And

pub struct AndQuery<'a> {
left: Box<dyn Query<'a>>,
right: Box<dyn Query<'a>>,
}

impl<'a> Query<'a> for AndQuery<'a> {
fn matches(&self, store: &Store, thing: &'_ Thing) -> bool {
self.left.matches(store, thing) && self.right.matches(store, thing)
}
}

// *** Or

pub struct OrQuery<'a> {
left: Box<dyn Query<'a>>,
right: Box<dyn Query<'a>>,
}

impl<'a> Query<'a> for OrQuery<'a> {
fn matches(&self, store: &Store, thing: &'_ Thing) -> bool {
self.left.matches(store, thing) || self.right.matches(store, thing)
}
}

// *** Xor

pub struct XorQuery<'a> {
left: Box<dyn Query<'a>>,
right: Box<dyn Query<'a>>,
}

impl<'a> Query<'a> for XorQuery<'a> {
fn matches(&self, store: &Store, thing: &'_ Thing) -> bool {
self.left.matches(store, thing) != self.right.matches(store, thing)
}
}

// * The Query<'a> parser

/**
Queries in Tkacz are made by combining Query<'a>s. The standard
format is Query<'a>:argument, for example:
authors:Foucault
:MyCollection
context:SomeContext
title:"*lambda*"
Some Query<'a>s allow for a more complex structures, with (eg) comparison operators:
date>2020-01-01
in:authors:Foucault
The Query<'a> parser has macros. Some non-alphabetic characters expand
to Query<'a>s. The most simple example is tag selection with #some-tag,
which expands to
in:(tag)some-tag
The parser also recognizes the classic boolean infix operators
`and`, `or`, and `xor` (aliased to &, |, !=) and the prefix not, !.
*/

pub struct QueryParser {}
80 changes: 80 additions & 0 deletions src/store.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
use crate::*;
use std::path::{Path, PathBuf};
use std::{fmt, fs, io};

// * The Store type

/// A Store
pub struct Store {
path: PathBuf,
writable: bool,
pub(crate) things: std::vec::Vec<Thing>,
}

// * Implementation

impl<'a> Store {
/// Open an existing Tkacz store.
pub fn open(path: &Path, read_only: bool) -> Result<Store, StoreAccessError> {
let metadata = fs::metadata(path)?;
if metadata.is_dir() {
let ret = Store {
path: path.to_path_buf(),
writable: !(read_only || metadata.permissions().readonly()),
things: std::vec!(),
};
return Ok(ret);
} else {
Err(StoreAccessError::new("Not a directory.".to_string()))
}
}

/// Initialize a new store into an existing, empty directory.
pub fn init(path: &Path) -> Result<(), StoreAccessError> {
let metadata = fs::metadata(path)?;
if !metadata.is_dir() {
Err(StoreAccessError::new("Not a directory.".to_string()))
} else if metadata.permissions().readonly() {
Err(StoreAccessError::new("Not writable.".to_string()))
} else if fs::read_dir(path)?.next().is_some() {
Err(StoreAccessError::new("Not empty.".to_string()))
} else {
// Todo create store.
Ok(())
}
}
/// Add a [Thing] to that store.
pub fn new_thing(&mut self, name: String) -> &mut Thing {
let id = self.things.len();
self.things.push(Thing { id: id as Id, name });
&mut self.things[id]
}
}

// * Errors

#[derive(Debug, Clone)]
/// Errors raised when accessing stores.
pub struct StoreAccessError {
msg: String,
}

impl StoreAccessError {
fn new(msg: String) -> StoreAccessError {
StoreAccessError { msg }
}
}

impl fmt::Display for StoreAccessError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "[StoreAccessError] {}", self.msg)
}
}

impl From<io::Error> for StoreAccessError {
fn from(error: io::Error) -> Self {
StoreAccessError {
msg: format!("IO Error: {}", error).to_string(),
}
}
}
Loading

0 comments on commit ddcd495

Please sign in to comment.