All files / src/draw/glyph elbows.ts

100% Statements 56/56
100% Branches 5/5
100% Functions 4/4
100% Lines 56/56

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 1261x 1x 1x 1x 1x     1x 4x 4x 4x 4x                             1x             1x 1x 1x 1x           1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x                             1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x                                                       1x   1656x 1656x 1656x 1656x 1656x 1656x  
import {Record} from '#util'
import {dual, K, type EndoOf} from '#Function'
import {segmentString} from '#String'
import {type TupleOf} from 'effect/Types'
import {elbowDirections} from '../direction.js'
import type {CornerDirection, ElbowSet} from './types.js'
 
const _replaceElbow = (
  set: ElbowSet,
  direction: CornerDirection,
  glyph: string,
): ElbowSet => Record.modify(set, direction, K(glyph))
 
/**
 * Given a direction and a glyph, replaces the elbow at this direction in a given
 * elbow set with the given glyph and returns the new elbow set.
 *
 * At the key `named` you will find a version that does the same but accepts a
 * _name_ of an elbow set instead of an elbow set.
 * @param set Elbow set to change.
 * @param direction A {@link CornerDirection} of the glyph to be changed.
 * @param glyph String of new glyph.
 * @returns Updated elbow set.
 * @category drawing
 * @function
 */
export const replaceElbow: {
  (set: ElbowSet, direction: CornerDirection, glyph: string): ElbowSet
  (direction: CornerDirection, glyph: string): EndoOf<ElbowSet>
  named: (
    direction: CornerDirection,
    glyph: string,
  ) => (name: ElbowSetName) => ElbowSet
} = Object.assign(dual(3, _replaceElbow), {
  named: (direction: CornerDirection, glyph: string) => (name: ElbowSetName) =>
    _replaceElbow(elbowSet(name), direction, glyph),
})
 
/**
 * Names of all elbow sets.
 * @category drawing
 */
export const elbowSetNames = [
  'ascii',
  'diagonal',
  'double',
  'halfSolid',
  'halfSolidNear',
  'halfSolidFar',
  'hDouble',
  'hThick',
  'round',
  'solid',
  'space',
  'thick',
  'thin',
  'vDouble',
  'vThick',
] as const
 
/**
 * The type of a elbow set name.
 * @category drawing
 */
export type ElbowSetName = (typeof elbowSetNames)[number]
 
/**
 * A record of all elbow sets. An elbow set has an elbow defined for each elbow
 * direction. The elbows are grouped into sets by style.
 * @category drawing
 */
export type ElbowSets = Record<ElbowSetName, ElbowSet>
 
const elbowSets: ElbowSets = {
  ascii: fromQuad(`..''`),
  diagonal: {topLeft: '╱', topRight: '╲', bottomLeft: '╲', bottomRight: '╱'},
  double: fromQuad('╔╗╚╝'),
  hDouble: fromQuad('╒╕╘╛'),
  hThick: fromQuad('┍┑┕┙'),
  round: fromQuad('╭╮╰╯'),
  solid: Record.monoRecord('█')(...elbowDirections),
  space: Record.monoRecord(' ')(...elbowDirections),
  thick: fromQuad('┏┓┗┛'),
  thin: fromQuad('┌┐└┘'),
  vDouble: fromQuad('╓╖╙╜'),
  vThick: fromQuad('┎┒┖┚'),
  halfSolid: fromQuad('▞▚▚▞'),
  halfSolidNear: fromQuad('▗▖▝▘'),
  halfSolidFar: fromQuad('▛▜▙▟'),
}
 
/**
 * Get an elbow set by name.
 *
 * You can mix and match sets. For example if you need a set of elbows for a box
 * where all borders are thin lines except the bottom which is a thick line,
 * you could:
 *
 * ```ts
 * import {Draw} from 'effect-tree'
 *
 * const myElbowSet: Draw.ElbowSet = {
 *   ...Struct.pick(Draw.elbowSet('thin'), ...Draw.topElbows),
 *   ...Struct.pick(Draw.elbowSet('hThick'), ...Draw.bottomElbows),
 * }
 * ```
 *
 * And your elbows will be thin, except for the bottom:
 *
 * ```txt
 *    topLeft ┌ ┐ topRight
 *
 * bottomLeft ┕ ┙ bottomRight
 * ```
 * @category drawing
 * @function
 */
export const elbowSet = (name: ElbowSetName): ElbowSet => elbowSets[name]
 
function fromQuad(s: string): ElbowSet {
  const [topLeft, topRight, bottomLeft, bottomRight] = segmentString(
    s,
  ) as TupleOf<4, string>
  return {topLeft, topRight, bottomRight, bottomLeft}
}