trevorld / bittermelon

Compare d7f4aa1 ... +21 ... 9477f87

No flags found

Use flags to group coverage reports by test type, project and/or folders.
Then setup custom commit statuses and notifications for each flag.

e.g., #unittest #integration

#production #enterprise

#frontend #backend

Learn more about Codecov Flags here.


@@ -30,7 +30,12 @@
Loading
30 30
}
31 31
32 32
#' @rdname unicode_utilities
33 +
#' @param pua_combining Additional Unicode code points to be considered
34 +
#'                      as a \dQuote{combining} character such as characters
35 +
#'                      defined in the Private Use Area (PUA) of a font.
33 36
#' @export
34 -
is_combining_character <- function(x) {
35 -
    Unicode::u_char_property(x, "Canonical_Combining_Class") > 0L
37 +
is_combining_character <- function(x, pua_combining = character(0)) {
38 +
    (Unicode::u_char_property(x, "Canonical_Combining_Class") > 0L) |
39 +
    (Unicode::u_char_property(x, "General_Category") == "Me") |
40 +
    (x %in% pua_combining)
36 41
}

@@ -33,12 +33,27 @@
Loading
33 33
}
34 34
35 35
#' @inheritParams as_bm_list
36 +
#' @inheritParams cbind.bm_bitmap
37 +
#' @inheritParams rbind.bm_bitmap
36 38
#' @rdname as_bm_bitmap
37 -
#' @param direction For horizontal binding either "left-to-right" (default) or its aliases "ltr" and "lr"
39 +
#' @param direction For purely horizontal binding either "left-to-right" (default) or its aliases "ltr" and "lr"
38 40
#'                  OR "right-to-left" or its aliases "rtl" and "rl".
39 -
#'                  For vertical binding either "top-to-bottom" (default) or its aliases "ttb" and "tb"
41 +
#'                  For purley vertical binding either "top-to-bottom" (default) or its aliases "ttb" and "tb"
40 42
#'                  OR "bottom-to-top" or its aliases "btt" and "bt".
43 +
#'                  For character vectors of length greater than one: for first horizontal binding within
44 +
#'                  values in the vector
45 +
#'                  and then vertical binding across values in the vector "left-to-right, top-to-bottom" (default)
46 +
#'                  or its aliases "lrtb" and "lr-tb"; "left-to-right, bottom-to-top" or its aliases "lrbt" and "lr-bt";
47 +
#'                  "right-to-left, top-to-bottom" or its aliases "rltb" and "rl-tb"; or
48 +
#'                  "right-to-left, bottom-to-top" or its aliases "rlbt" and "rl-bt".
49 +
#'                  For first vertical binding within values in the vector and then horizontal binding across values
50 +
#'                  "top-to-bottom, left-to-right" or its aliases "tblr" and "tb-lr";
51 +
#'                  "top-to-bottom, right-to-left" or its aliases "tbrl" and "tb-rl";
52 +
#'                  "bottom-to-top, left-to-right" or its aliases "btlr" and "bt-lr"; or
53 +
#'                  "bottom-to-top, right-to-left" or its aliases "btrl" and "bt-rl".
41 54
#'                  The `direction` argument is not case-sensitive.
55 +
#' @param compose Compose graphemes using [bm_compose()].
56 +
#' @param pua_combining Passed to [bm_compose()].
42 57
#' @examples
43 58
#'   font_file <- system.file("fonts/fixed/4x6.yaff.gz", package = "bittermelon")
44 59
#'   font <- read_yaff(font_file)
@@ -48,22 +63,102 @@
Loading
48 63
#'   print(bm, px = px_ascii)
49 64
#' @export
50 65
as_bm_bitmap.character <- function(x, ...,
51 -
                                   direction = "left-to-right",
52 -
                                   font = bm_font()) {
53 -
    bml <- as_bm_list(x, font = font)
54 -
55 -
    is_ltr <- c(tolower(direction) %in% c("left-to-right", "ltr", "lr"))
56 -
    is_rtl <- c(tolower(direction) %in% c("right-to-left", "rtl", "rl"))
57 -
    is_ttb <- c(tolower(direction) %in% c("top-to-bottom", "ttb", "tb"))
58 -
    is_bbt <- c(tolower(direction) %in% c("bottom-to-top", "bbt", "bt"))
59 -
    stopifnot(is_ltr || is_rtl || is_ttb || is_bbt)
60 -
    if (is_ltr || is_rtl)
61 -
        bm <- bm_call(bml, cbind, direction = direction)
62 -
    else
63 -
        bm <- bm_call(bml, rbind, direction = direction)
66 +
                                   direction = "left-to-right, top-to-bottom",
67 +
                                   font = bm_font(),
68 +
                                   hjust = "left",
69 +
                                   vjust = "top",
70 +
                                   compose = TRUE,
71 +
                                   pua_combining = character(0)) {
72 +
73 +
    direction <- tolower(direction)
74 +
    check_direction(direction)
75 +
    direction_type <- get_direction_type(direction)
76 +
    if (direction_type == "h") {
77 +
        bml <- as_bm_list(x, font = font)
78 +
        if (compose) bml <- bm_compose(bml, pua_combining)
79 +
        bm <- bm_call(bml, cbind, direction = direction, vjust = vjust)
80 +
    } else if (direction_type == "v") {
81 +
        bml <- as_bm_list(x, font = font)
82 +
        if (compose) bml <- bm_compose(bml, pua_combining)
83 +
        bm <- bm_call(bml, rbind, direction = direction, hjust = hjust)
84 +
    } else if (direction_type == "hv") {
85 +
        hdirection <- get_h_direction(direction)
86 +
        vdirection <- get_v_direction(direction)
87 +
        l <- lapply(x, as_bm_list, font = font)
88 +
        if (compose) l <- lapply(l, bm_compose, pua_combining)
89 +
        l <- lapply(l, add_space, font = font)
90 +
        l <- lapply(l, function(x) bm_call(x, cbind, direction = hdirection, vjust = vjust))
91 +
        bm <- bm_call(l, rbind, direction = vdirection, hjust = hjust)
92 +
    } else { # vh
93 +
        hdirection <- get_h_direction(direction)
94 +
        vdirection <- get_v_direction(direction)
95 +
        l <- lapply(x, as_bm_list, font = font)
96 +
        if (compose) l <- lapply(l, bm_compose, pua_combining)
97 +
        l <- lapply(l, add_space, font = font)
98 +
        l <- lapply(l, function(x) bm_call(x, rbind, direction = vdirection, hjust = hjust))
99 +
        bm <- bm_call(l, cbind, direction = hdirection, vjust = vjust)
100 +
    }
64 101
    bm
65 102
}
66 103
104 +
check_direction <- function(direction) {
105 +
106 +
    stopifnot(direction %in% c("left-to-right", "ltr", "lr",
107 +
                               "right-to-left", "rtl", "rl",
108 +
                               "top-to-bottom", "ttb", "tb",
109 +
                               "bottom-to-top", "btt", "bt",
110 +
                               "left-to-right, top-to-bottom", "lrtb", "lr-tb",
111 +
                               "left-to-right, bottom-to-top", "lrbt", "lr-bt",
112 +
                               "right-to-left, top-to-bottom", "rltb", "rl-tb",
113 +
                               "right-to-left, bottom-to-top", "rlbt", "rl-bt",
114 +
                               "top-to-bottom, left-to-right", "tblr", "tb-lr",
115 +
                               "top-to-bottom, right-to-left", "tbrl", "tb-rl",
116 +
                               "bottom-to-top, left-to-right", "btlr", "bt-lr",
117 +
                               "bottom-to-top, right-to-left", "btrl", "bt-rl"))
118 +
}
119 +
120 +
get_direction_type <- function(direction) {
121 +
    is_h <- direction %in% c("left-to-right", "ltr", "lr", "right-to-left", "rtl", "rl")
122 +
    is_v <- direction %in% c("top-to-bottom", "ttb", "tb", "bottom-to-top", "btt", "bt")
123 +
    is_hv <- direction %in% c("left-to-right, top-to-bottom", "lrtb", "lr-tb",
124 +
                              "left-to-right, bottom-to-top", "lrbt", "lr-bt",
125 +
                              "right-to-left, top-to-bottom", "rltb", "rl-tb",
126 +
                              "right-to-left, bottom-to-top", "rlbt", "rl-bt")
127 +
128 +
    if (is_h) {
129 +
        "h"
130 +
    } else if (is_v) {
131 +
       "v"
132 +
    } else if (is_hv) {
133 +
        "hv"
134 +
    } else {
135 +
        "vh"
136 +
    }
137 +
}
138 +
139 +
get_h_direction <- function(direction) {
140 +
    if (grepl("left-to-right|ltr|lr", direction))
141 +
        "left-to-right"
142 +
    else
143 +
        "right-to-left"
144 +
}
145 +
146 +
get_v_direction <- function(direction) {
147 +
    if (grepl("top-to-bottom|ttb|tb", direction))
148 +
        "top-to-bottom"
149 +
    else
150 +
        "bottom-to-top"
151 +
}
152 +
153 +
# If a line of text is empty fill it with "space" instead
154 +
add_space <- function(bml, font) {
155 +
    if (length(bml) > 0) {
156 +
        bml
157 +
    } else {
158 +
        font["U+0020"]
159 +
    }
160 +
}
161 +
67 162
#' @rdname as_bm_bitmap
68 163
#' @param width Desired width of bitmap
69 164
#' @param height Desired height of bitmap

@@ -27,6 +27,11 @@
Loading
27 27
}
28 28
29 29
bm_expand_bitmap <- function(bitmap, width = 1L, height = 1L) {
30 +
    if (nrow(bitmap) == 0L || ncol(bitmap) == 0L) {
31 +
        nr <- height * nrow(bitmap)
32 +
        nc <- width * ncol(bitmap)
33 +
        return(bm_bitmap(matrix(integer(), nrow = nr, ncol = nc)))
34 +
    }
30 35
    if (width != 1L) {
31 36
        l <- lapply(seq_len(ncol(bitmap)),
32 37
                    function(j) bitmap[, j, drop = FALSE])

@@ -42,6 +42,7 @@
Loading
42 42
#' @export
43 43
as_bm_list.character <- function(x, ..., font = bm_font()) {
44 44
    x <- paste(x, collapse = "")
45 +
    if (nchar(x) == 0) return(bm_list())
45 46
    ucp <- str2ucp(x)
46 47
    bml <- as_bm_list(font[ucp])
47 48
    stopifnot(!any(sapply(bml, is.null)))

@@ -3,30 +3,37 @@
Loading
3 3
#' `read_monobit()` reads in bitmap font file as a [bm_font()] object while `write_monobit()`
4 4
#' writes a [bm_font()] object as a bitmap font file.
5 5
#' It uses the file extension to determine the appropriate bitmap font format to use.
6 +
#' `update_monobit()` downloads an updated version of `monobit`.
6 7
#'
7 8
#' `read_monobit()` and `write_monobit()` require Python v3.6 or greater available on the system.
8 9
#' `read_monobit()` and `write_monobit()` uses `monobit`'s `convert.py` script to convert to/from
9 10
#' the yaff font format which this package can natively read/write from/to.
10 -
#' Note `monobit` is alpha level software which may not always work
11 -
#' (in particular font export may be buggy).
11 +
#' This package embeds an older, smaller version of `monobit`.
12 +
#' Use `update_monobit()` to download a newer, better version of `monobit`
13 +
#' (which unfortunately is too large to embed within this package).
12 14
#'
13 15
#' @param file A character string of a filename.
14 16
#' @param font A [bm_font()] object.
17 +
#' @param monobit_path Which directory containing `monobit` to use.
18 +
#'                     Default will be to look in `file.path(rappdirs::user_config_dir("bittermelon"), "monobit")`,
19 +
#'                     `file.path(rappdirs::site_config_dir("bittermelon"), "monobit")`, and
20 +
#'                    `system.file("monobit", package = "bittermelon")` (in that order).
15 21
#' @param quietly If `TRUE` suppress any standard output/error from `monobit`.
22 +
#' @param site If `TRUE` try to install into `rappdirs::site_config_dir("bittermelon")`
23 +
#'             instead of `rappdirs::user_config_dir("bittermelon")`.
24 +
#'             Note this may require administrator privileges.
16 25
#' @examples
17 26
#'  if (findpython::can_find_python_cmd(minimum_version = "3.6")) {
18 27
#'    font_file <- system.file("fonts/spleen/spleen-8x16.hex.gz", package = "bittermelon")
19 28
#'    tempfile <- tempfile(fileext = ".hex")
20 29
#'    writeLines(readLines(font_file), tempfile)
21 30
#'
22 -
#'    try({ # `monobit` is alpha level software which may not always work
23 -
#'      font <- read_monobit(tempfile)
24 -
#'      capital_r <- font[[str2ucp("R")]]
25 -
#'      print(capital_r, px = c(".", "#"))
31 +
#'    font <- read_monobit(tempfile)
32 +
#'    capital_r <- font[[str2ucp("R")]]
33 +
#'    print(capital_r, px = c(".", "#"))
26 34
#'
27 -
#'      filename <- tempfile(fileext = ".yaff")
28 -
#'      write_monobit(font, filename)
29 -
#'    })
35 +
#'    filename <- tempfile(fileext = ".yaff")
36 +
#'    write_monobit(font, filename)
30 37
#'  }
31 38
#' @seealso [bm_font()] for more information about bitmap font objects.
32 39
#'    [read_hex()], [write_hex()], [read_yaff()], [write_yaff()] for pure R bitmap font readers and writers.
@@ -35,37 +42,71 @@
Loading
35 42
#'          as a side effect writes `file`.
36 43
#' @rdname monobit
37 44
#' @export
38 -
read_monobit <- function(file, quietly = FALSE) {
45 +
read_monobit <- function(file, quietly = FALSE,
46 +
                         monobit_path = getOption("bittermelon.monobit_path", NULL)) {
39 47
    stopifnot(!missing(file))
40 48
    if (quietly)
41 49
        stdout <- stderr <- FALSE
42 50
    else
43 51
        stdout <- stderr <- ""
44 52
    python <- findpython::find_python_cmd(minimum_version = "3.6")
45 -
    convert <- system.file("monobit/convert.py", package = "bittermelon", mustWork = TRUE)
53 +
    monobit_path <- monobit_path %||% get_monobit_path()
54 +
    convert <- file.path(monobit_path, "convert.py")
46 55
47 -
    tfile <- tempfile(fileext = ".yaff")
56 +
    tfile <- tempfile(fileext = ".yaff.gz")
48 57
    on.exit(unlink(tfile))
49 58
50 59
    system2(python, c(convert, file, tfile), stdout = stdout, stderr = stderr)
51 60
    read_yaff(tfile)
52 61
}
53 62
63 +
get_monobit_path <- function() {
64 +
    user_monobit_path <- file.path(rappdirs::user_config_dir("bittermelon"), "monobit")
65 +
    if (dir.exists(user_monobit_path))
66 +
        return(user_monobit_path)
67 +
68 +
    site_monobit_path <- file.path(rappdirs::site_config_dir("bittermelon"), "monobit")
69 +
    if (dir.exists(site_monobit_path))
70 +
            return(site_monobit_path)
71 +
72 +
    system.file("monobit", package = "bittermelon", mustWork = TRUE)
73 +
}
74 +
54 75
#' @rdname monobit
55 76
#' @export
56 -
write_monobit <- function(font, file, quietly = FALSE) {
77 +
write_monobit <- function(font, file, quietly = FALSE,
78 +
                          monobit_path = getOption("bittermelon.monobit_path", NULL)) {
57 79
    stopifnot(!missing(font), !missing(file))
58 80
    if (quietly)
59 81
        stdout <- stderr <- FALSE
60 82
    else
61 83
        stdout <- stderr <- ""
62 84
    python <- findpython::find_python_cmd(minimum_version = "3.6")
63 -
    convert <- system.file("monobit/convert.py", package = "bittermelon", mustWork = TRUE)
85 +
    monobit_path <- monobit_path %||% get_monobit_path()
86 +
    convert <- file.path(monobit_path, "convert.py")
64 87
65 -
    tfile <- tempfile(fileext = ".yaff")
88 +
    tfile <- tempfile(fileext = ".yaff.gz")
66 89
    on.exit(unlink(tfile))
67 90
68 -
    write_yaff(font, tfile)
91 +
    write_yaff(font, gzfile(tfile))
69 92
    system2(python, c(convert, tfile, file), stdout = stdout, stderr = stderr)
70 93
    invisible(invisible(NULL))
71 94
}
95 +
96 +
#' @rdname monobit
97 +
#' @export
98 +
update_monobit <- function(site = FALSE) {
99 +
    if (!requireNamespace("git2r"))
100 +
        stop(paste("Requires suggested package {git2r}.",
101 +
                   'Use `install.packages("git2r")` to install it.'))
102 +
103 +
    if (site)
104 +
        monobit_path <- file.path(rappdirs::site_config_dir("bittermelon"), "monobit")
105 +
    else
106 +
        monobit_path <- file.path(rappdirs::user_config_dir("bittermelon"), "monobit")
107 +
108 +
    if (dir.exists(monobit_path))
109 +
        git2r::pull(monobit_path)
110 +
    else
111 +
        git2r::clone("https://github.com/robhagemans/monobit.git", monobit_path)
112 +
}

Click to load this diff.
Loading diff...

Learn more Showing 2 files with coverage changes found.

New file R/bm_compose.R
New
Loading file...
Changes in R/bind.R
-2
+2
Loading file...

23 Commits

Hiding 21 contexual commits
+1 Files
+93
+80
+13
Files Coverage
R -0.50% 91.80%
Project Totals (39 files) 91.80%
Loading