cookbook home ~ main site ~ links ~ podcast ~ mastodon

Step By Step Code Example Prototype V9

Details

EXAMPLE

fn main() { // Full source code
let alfa = String::from("apple");
let charlie = widget(alfa);
println!("charlie is {charlie}");
}
fn widget(thing: String) -> String {
println!("widget got {thing}");
let bravo = String::from("berry");
bravo
}
הההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההה
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX




HTML Source

<!-- prettier-ignore -->
<div id="wrapper">
<div id="editor"></div>
</div>

CSS Source

#editor {
  min-height: 22rem;
}

#stepByStepRangeSlider {
  min-width: 20rem;
}

JavaScript Source

const makeElement = (
  _type,
  _id,
  _html,
  _childOf,
  _event,
  _function,
  _classes
) => {
  const newElement = document.createElement(_type)
  newElement.id = _id
  newElement.innerHTML = _html
  window[_childOf].appendChild(newElement)
  if (_event !== null) {
    newElement.addEventListener(_event, _function)
  }
  if (_classes) {
    newElement.classList.add(_classes)
  }
}

const handleNextButtonClick = () => {
  if (c.set < c.sets.length - 1) {
    updateEverything(c.set + 1)
  }
}

const handleNumberButtonClick = (event) => {
  const newIndex = parseInt(event.target.id.split('_')[1])
  updateEverything(newIndex)
}

const handlePreviousButtonClick = () => {
  if (c.set > 0) {
    updateEverything(c.set - 1)
  }
}

const makeNextButton = () => {
  makeElement(
    'button',
    'stepByStepNextButton',
    '-&gt;',
    'wrapper',
    'click',
    handleNextButtonClick,
    'stepByStepButton'
  )
}

const makeNumberButtons = () => {
  for (let i = 0; i < c.sets.length; i++) {
    let buttonText = i

    if (i === 0) {
      buttonText = 'Start'
    } else if (i === c.sets.length - 1) {
      buttonText = 'Complete'
    }

    makeElement(
      'button',
      `stepByStepNumberButton_${i}`,
      buttonText,
      'wrapper',
      'click',
      handleNumberButtonClick,
      'stepByStepButton'
    )
  }
}

const makePreviousButton = () => {
  makeElement(
    'button',
    'stepByStepPreviousButton',
    '&lt;-',
    'wrapper',
    'click',
    handlePreviousButtonClick,
    'stepByStepButton'
  )
}

const handleRangeSliderChange = (event) => {
  updateEverything(parseInt(event.target.value))
}

const makeRangeSlider = () => {
  const newEl = document.createElement('input')
  newEl.id = 'stepByStepRangeSlider'
  newEl.type = 'range'
  newEl.min = 0
  newEl.max = 9
  newEl.value = 0
  newEl.addEventListener('input', handleRangeSliderChange)
  window.wrapper.appendChild(newEl)
}

const loadLines = () => {
  c.lines = c.source.split('\n')
}

const removeHighlights = () => {
  // console.log('removeHighlights')

  // bail if no lines were selected
  //
  if (c.sets[c.set].highlights.length === 0) {
    c.styleOverride.innerHTML = `.ace-monokai .ace_line .ace_comment { color: #eee; }`
    return
  }

  const selectors = [
    '.ace_keyword',
    '.ace_lparen',
    '.ace_source',
    '.ace_rust',
    '.ace_paren',
    '.ace_function',
    '.ace_entity',
    '.ace_identifier',
    '.ace_operator',
    '.ace_support',
    '.ace_constant',
    '.ace_quoted',
    '.ace_string',
    '.ace_double',
    '.ace_punctuation',
    '.ace_rparen',
  ]

  // console.log(c.lines.length)

  const removers = []

  for (let i = 0; i < c.lines.length; i++) {
    const lineNumber = i + 1
    if (!c.sets[c.set].highlights.includes(lineNumber)) {
      for (let x = 0; x < selectors.length; x++) {
        removers.push(
          `.ace-monokai .ace_line:nth-child(${lineNumber}) ${selectors[x]} { color: #667; }`
        )
        // console.log(selectors[x])
      }
      removers.push(
        `.ace-monokai .ace_line:nth-child(${lineNumber}) .ace_comment { color: #eee; }`
      )
    }
    // set the comment color for the lines with content
    else {
      removers.push(
        `.ace-monokai .ace_line:nth-child(${lineNumber}) .ace_comment { color: #eee; }`
      )
    }
  }

  c.styleOverride.innerHTML = `${removers.join(' ')}`
  // console.log(c.styleOverride.innerHTML)
}

const updateContent = () => {
  parts = []
  for (let i = 0; i < c.lines.length; i++) {
    if (c.sets[c.set].lines.includes(i + 1)) {
      parts.push(`${c.lines[i]}`)
    } else {
      parts.push('')
    }
  }

  // add the notes
  const noteParts = c.sets[c.set].note.split('\n').filter((line) => line !== '')
  for (let n = 0; n < noteParts.length; n++) {
    const outputLine = n + c.sets[c.set].noteCoords[0] - 1
    const padding = c.sets[c.set].noteCoords[1] - parts[outputLine].length - 1
    // console.log(padding)
    for (let pad = 0; pad < padding; pad++) {
      parts[outputLine] += ' '
    }
    parts[outputLine] += noteParts[n]
  }

  if (c.sets[c.set].overrides) {
    for (let o = 0; o < c.sets[c.set].overrides.length; o++) {
      const override = c.sets[c.set].overrides[0]
      parts[override.line - 1] = override.text
    }
  }

  c.editor.setValue(parts.join('\n'), 1)
}

const updateEverything = (set) => {
  c.set = set
  window.stepByStepRangeSlider.value = set
  updateContent()
  removeHighlights()
}

const init = () => {
  loadLines()
  c.editor = ace.edit('editor')
  c.editor.setTheme('ace/theme/monokai')
  c.editor.session.setMode('ace/mode/rust')
  c.editor.setHighlightActiveLine(false)
  c.styleOverride = document.createElement('style')
  document.body.appendChild(c.styleOverride)
  makePreviousButton()
  //makeNumberButtons()
  makeRangeSlider()
  makeNextButton()
  updateEverything(0)
}

document.addEventListener('DOMContentLoaded', init)

JSON Data Source

{
  "note": "Example JSON data file"
}

Config JS Source

// This file can be used to represent
// and data that should be held outside
// of the main script

const c = {
  source: `fn main() { 
  let alfa = String::from("apple"); 
  let charlie = widget(alfa); 
  println!("charlie is {charlie}"); 
} 
 
fn widget(thing: String) -> String { 
  println!("widget got {thing}"); 
  let bravo = String::from("berry"); 
  bravo 
}`,
  sets: [
    {
      lines: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
      highlights: [],
      note: `// Full source code`,
      noteCoords: [1, 40],
    },

    {
      lines: [7, 11],
      highlights: [7, 11],
      overrides: [{ line: 7, text: `fn widget() {` }],
      note: `
// Start by creating a basic \`widget()\` 
// function


`,
      noteCoords: [3, 0],
    },

    {
      lines: [7, 11],
      highlights: [7],
      overrides: [{ line: 7, text: `fn widget(thing: String) {` }],
      note: `
// Setup \`widget\` to accept a \`String\` 
// argument and bind it to the local 
// variable \`thing\`

`,
      noteCoords: [3, 0],
    },

    {
      lines: [7, 11],
      highlights: [7],
      overrides: [{ line: 7, text: `fn widget(thing: String) -> String {` }],
      note: `
// Add a \`String\` return type



`,
      noteCoords: [3, 0],
    },

    {
      lines: [7, 8, 11],
      highlights: [8],
      note: `
// Create a \`println!()\` output that shows
// the \`thing\` variable that gets passed
// into the function

`,
      noteCoords: [3, 0],
    },

    {
      lines: [7, 8, 9, 10, 11],
      highlights: [9, 10],
      note: `
// Create a \`bravo\` variable and assign it a 
// \`String\` so it matches the return type then 
// return it as the last expression of the function

`,
      noteCoords: [3, 0],
    },

    {
      lines: [1, 2, 5, 7, 8, 9, 10, 11],
      highlights: [1, 2, 5],
      overrides: [],
      noteCoords: [1, 40],
      note: `
// Create the \`main()\` function and a
// variable named \`alfa\` with a \`String\` 
// bound to it. 

`,
    },

    {
      lines: [1, 2, 3, 5, 7, 8, 9, 10, 11],
      highlights: [3],
      overrides: [],
      noteCoords: [1, 40],
      note: `
// Add a variable named \`charlie\` that 
// passes the \`alfa\` variable to \`widget\`

`,
    },

    {
      lines: [1, 2, 3, 4, 5, 7, 8, 9, 10, 11],
      highlights: [4],
      overrides: [],
      noteCoords: [1, 40],
      note: `
// Finally print out the value in 
// \`charlie\` to show the value it
// received from \`widget\`

`,
    },

    {
      lines: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
      highlights: [],
      overrides: [],
      note: `// Click run to see the output`,
      noteCoords: [1, 40],
    },
  ],
}