R/shiny_chunk.r

Defines functions update.all.chunk.ui set.shiny.chunk save.shiny.chunk data.shiny.chunk edit.shiny.chunk output.shiny.chunk solution.shiny.chunk restore.shiny.chunk help.shiny.chunk hint.shiny.chunk proceed.with.successfuly.checked.chunk check.shiny.chunk run.line.shiny.chunk run.shiny.chunk make.chunk.handlers make.chunk.task.ui make.chunk.output.ui make.chunk.input.ui get.chunk.ui update.chunk.ui set.nali.names make.chunk.nali make.initial.chunk.ui chunk.fluidRow

chunk.fluidRow = function(...) {
  li = list(...)
  names(li) = NULL
  li
}

# set all information for the initial chunk ui
# when a problem set is started
make.initial.chunk.ui = function(chunk.ind, ps=get.ps()) {
  restore.point("make.initial.chunk.ui")
  chunk.name = ps$cdt$chunk.name[chunk.ind]
  nali = make.chunk.nali(chunk.name)
  ui = chunk.fluidRow(
    uiOutput(nali$chunkUI)
  )
  ps$cdt[["nali"]][[chunk.ind]] = nali
  ps$cdt[["ui"]][[chunk.ind]] = ui
  invisible(ui)
}

# Set names for chunk widgets
make.chunk.nali = function(chunk.name, chunk.ind=which(ps$cdt$chunk.name==chunk.name), ps = get.ps()) {
  restore.point("make.chunk.nali")
  name = gsub(" ","_",chunk.name,fixed=TRUE)
  name = gsub(".","_",name,fixed=TRUE)
  name = gsub(")","",name,fixed=TRUE)
  name = paste0("chunk_",name)

  base.names = c(
    "chunkUI", "editor","console","chunkout",
    "runLineKey","runKey","checkKey","hintKey","helpKey",
    "runLineBtn","runBtn","checkBtn","hintBtn","helpBtn","dataBtn",
    "outputBtn", "restoreBtn", "saveBtn",
    "editBtn","solutionBtn","revertBtn", "alertOut",
    "inputPanel","outputPanel"
  )
  nali = paste0(name,"_",base.names)
  names(nali) =  base.names
  nali = as.list(c(name=name, chunk.name=chunk.name, nali))
  nali$chunk.ind = chunk.ind
  nali
}

set.nali.names = function(x, nali) {
  restore.point("set.nali.names")
  ind = match(names(x), names(nali))
  names(x)[!is.na(ind)] = unlist(nali[ind[!is.na(ind)]])
  x
}

update.chunk.ui = function(chunk.ind, mode=ps$cdt$mode[chunk.ind], ps=get.ps(), session=ps$session, app=getApp()) {
  restore.point("update.chunk.ui")
  #browser()

  if (app$verbose)
    cat("\nupdate.chunk.ui: ", chunk.ind)
  ps$cdt$mode[chunk.ind] = mode
  ui = get.chunk.ui(chunk.ind, ps=ps)
  nali = ps$cdt$nali[[chunk.ind]]

  updateUI(session,nali$chunkUI, ui)
  if (app$verbose)
    cat("\nend update.chunk.ui\n")
}

# returns the ui for a chunk based on its current mode
# mode can be "input", "output", "hidden", "hidden.code"
# or "inactive"
get.chunk.ui = function(chunk.ind, ps=get.ps(),... ) {
  restore.point("make.chunkUI")
  mode = ps$cdt$mode[chunk.ind]
  if (mode=="input") {
    return(make.chunk.input.ui(chunk.ind=chunk.ind,...))
  } else if (mode=="output") {
    return(make.chunk.output.ui(chunk.ind=chunk.ind,...))
  } else if (mode=="inactive") {
    chunk.fluidRow(
      HTML("You must first solve the earlier chunks...")
    )
  } else  {
    chunk.fluidRow(
      HTML("Not shown")
    )
  }
}


make.chunk.input.ui = function(chunk.ind, theme="textmate", height=NULL, code.lines=NULL, fontSize=12, console.height=height, ps = get.ps()) {
  restore.point("make.chunk.input.ui")

  
  nali = ps$cdt$nali[[chunk.ind]]
  code = ps$cdt$stud.code[[chunk.ind]]

  if (is.null(code.lines))
    code.lines = length(sep.lines(code))+1

  if (is.null(height)) {
    height = max((fontSize * 1.25) * code.lines,30)+35
  }
  if (is.null(console.height)) {
    console.code.lines = min(code.lines,10)
    console.height = (fontSize * 1.25) * console.code.lines + 50
  }

  #cat(paste0("\n",nali$name, " height = ", height))



  if (ps$cdt$is.solved[chunk.ind]) {
    label = "was already solved"
  } else {
    label = "not yet solved"
  }

  solutionBtn  = NULL
  if (isTRUE(ps$show.solution.btn)) {
    solutionBtn=bsButton(nali$solutionBtn, "solution",size="extra-small")
  } else {
    solutionBtn  = NULL
  }
  if (isTRUE(ps$show.revert.btn)) {
    revertBtn=bsButton(nali$revertBtn, "original code",size="extra-small")
  } else {
    revertBtn  = NULL
  }

  if (isTRUE(ps$show.data.exp)) {
    dataBtn = bsButton(nali$dataBtn, "data", size="extra-small")
  } else {
    dataBtn  = NULL
  }

  if (isTRUE(ps$show.save.btn)) {
    saveBtn = bsButton(nali$saveBtn, "save",size="extra-small")
  } else {
    saveBtn = NULL
  }
  if (!ps$noeval) {
    button.row = chunk.fluidRow(
      bsButton(nali$checkBtn, "check",size="extra-small"),
      bsButton(nali$hintBtn, "hint", size="extra-small"),
      bsButton(nali$runBtn, "run chunk",size="extra-small"),
      dataBtn,
      saveBtn,
      solutionBtn,
      revertBtn
    )
    keys = list(runLineKey="Ctrl-Enter", helpKey="F1", runKey="Ctrl-R|Ctrl-Shift-Enter", hintKey="Ctrl-H", checkKey = "Ctrl-Alt-R|Ctrl-T")

  } else {
    button.row = chunk.fluidRow(
      bsButton(nali$checkBtn, "check",size="extra-small"),
      bsButton(nali$hintBtn, "hint", size="extra-small"),
      solutionBtn
    )
    keys = list(hintKey="Ctrl-H", checkKey = "Ctrl-Alt-R|Ctrl-T")
  }

  keys = set.nali.names(keys, nali)

  edit.row = chunk.fluidRow(
    aceEditor(nali$editor, code, mode="r",theme=theme, height=height, fontSize=13,hotkeys = keys, wordWrap=TRUE, debounce=10,autoComplete = "enabled"),
    aceEditor(nali$console, "", mode="r",theme="clouds", height=console.height, fontSize=13,hotkeys = NULL, wordWrap=TRUE, debounce=10, showLineNumbers=FALSE,highlightActiveLine=FALSE)
  )

  if (!identical(chunk.ind,ps$chunk.ind))
    set.shiny.chunk(chunk.ind)

  set.chunk.autocomp.observer(inputId = nali$editor, chunk.ind = chunk.ind)
  #aceAutocomplete(nali$editor)

  chunk.fluidRow(
    button.row,
    #bsAlert(nali$alertOut),
    uiOutput(nali$alertOut),
    edit.row
  )
}

make.chunk.output.ui = function(chunk.ind, ps = get.ps()) {
  restore.point("make.chunk.output.ui")

  nali = ps$cdt$nali[[chunk.ind]]
  code = ps$cdt$stud.code[[chunk.ind]]

  suspend.chunk.autocomp.observer(chunk.ind)
  
  if (isTRUE(ps$show.save.btn)) {
    saveBtn = bsButton(nali$saveBtn, "save", size="extra-small")
  } else {
    saveBtn = NULL
  }
  if (isTRUE(ps$show.data.exp)) {
    dataBtn = bsButton(nali$dataBtn, "data", size="extra-small")
  } else {
    dataBtn  = NULL
  }

  
  if (!ps$noeval) {
    button.row = chunk.fluidRow(
      bsButton(nali$editBtn, "edit",size="extra-small"),
      dataBtn,
      saveBtn
    )
  } else {
    button.row = chunk.fluidRow(
      bsButton(nali$editBtn, "edit",size="extra-small")
    )
  }

  is.solved = ps$cdt$is.solved[[chunk.ind]]
  mode = ps$cdt$mode[[chunk.ind]]
  #cat("\nbefore if (is.solved) {")
  #cat("code:\n", code)
  if (is.solved) {
    code = code
    opts = ps$cdt$chunk.opt[[chunk.ind]]
    
    preknit = 
        # noeval will always be preknit
        ps$noeval | 
        # don't preknit special output or if chunk option replace.sol=FALSE
        (ps$preknit & !(!is.null(opts[["output"]]) | is.false(opts$replace.sol)))
    
    if (preknit) {
      if (!is.null(opts[["output"]])) {
        html = HTML("<p> SPECIAL OUTPUT HERE <p>")
      } else {
        html = ps$cdt$sol.html[[chunk.ind]]
        html = HTML(html)
      }
    } else {
      # not preknitted (default)
      if (!is.null(opts[["output"]])) {
        html = chunk.special.output(code, chunk.ind, nali=nali, output=opts[["output"]], ps=ps)
      } else {
        html = chunk.to.html(code, chunk.ind, nali=nali)
        html = HTML(html)
      }
    }
    
    
  } else {
    
    if ((identical(code, ps$cdt$task.txt[[chunk.ind]]) | isTRUE(ps$noeval)) & !is.null(ps$cdt$task.html)) {
      # just show precompiled task
      html = ps$cdt$task.html[[chunk.ind]]
    } else {
      # compile no solution again
      if (ps$noeval) {
        task = ps$cdt$task.txt[[chunk.ind]]
        html = chunk.to.html(task, chunk.ind, eval=FALSE, nali=nali)
      } else {
        html = chunk.to.html(code, chunk.ind, eval=FALSE, nali=nali)
      }
      
    }
    
    html = HTML(html)
  }

  restore.point("make.chunk.output.ui.2")

  #cat("\nbefore chunk.fluidRow(")

  chunk.fluidRow(
    button.row,
    uiOutput(nali$alertOut),
    #bsAlert(nali$alertOut),
    html
  )
}


make.chunk.task.ui = function(...) {
  make.chunk.output.ui(...)
}

make.chunk.handlers = function(chunk.ind, nali = ps$cdt$nali[[chunk.ind]], ps=get.ps()) {
  restore.point("make.chunk.handlers")


  buttonHandler(nali$checkBtn, check.shiny.chunk, chunk.ind=chunk.ind)
  aceHotkeyHandler(nali$checkKey, check.shiny.chunk, chunk.ind=chunk.ind)
  buttonHandler(nali$hintBtn, hint.shiny.chunk, chunk.ind=chunk.ind)
  aceHotkeyHandler(nali$hintKey, hint.shiny.chunk, chunk.ind=chunk.ind)
  buttonHandler(nali$saveBtn, save.shiny.chunk, chunk.ind=chunk.ind)


  if (!ps$noeval) {
    buttonHandler(nali$runBtn, run.shiny.chunk, chunk.ind=chunk.ind)
    aceHotkeyHandler(nali$runKey, run.shiny.chunk, chunk.ind=chunk.ind)
    if (isTRUE(ps$show.data.exp))
      buttonHandler(nali$dataBtn, data.shiny.chunk, chunk.ind=chunk.ind)
    aceHotkeyHandler(nali$runLineKey, run.line.shiny.chunk, chunk.ind=chunk.ind)
    aceHotkeyHandler(nali$helpKey, help.shiny.chunk, chunk.ind=chunk.ind)
  }

  if (isTRUE(ps$show.solution.btn))
    buttonHandler(nali$solutionBtn, solution.shiny.chunk, chunk.ind=chunk.ind)

  if (isTRUE(ps$show.revert.btn))
    buttonHandler(nali$revertBtn, restore.shiny.chunk, chunk.ind=chunk.ind)

  
  buttonHandler(nali$editBtn, edit.shiny.chunk, chunk.ind=chunk.ind)
}


run.shiny.chunk = function(chunk.ind,...,session=ps$session, ps=get.ps()) {
  set.shiny.chunk(chunk.ind)
  envir=ps$stud.env; in.R.console=is.null(ps$nali$console)
  restore.point("run.shiny.chunk")

  if (in.R.console) {
    eval.in.console(ps$code, envir=envir)
  } else {
    eval.in.ace.console(ps$code, envir=envir, consoleId=ps$nali$console,session=ps$session)
  }
}

run.line.shiny.chunk = function(chunk.ind, range=NULL, selection=NULL,...,session=ps$session,ps=get.ps()) {
  set.shiny.chunk(chunk.ind, cursor=range$start, selection=selection)
  envir=ps$stud.env; in.R.console=is.null(ps$nali$console)
  restore.point("run.line.shiny.chunk")

  if (ps$selection == "") {
    txt = sep.lines(ps$code)
    if (length(ps$cursor)>0) {
      txt = txt[ps$cursor$row+1]
    }
  } else {
    txt = ps$selection
  }
  if (in.R.console) {
    eval.in.console(txt, envir=envir)
  } else {
    eval.in.ace.console(txt, envir=envir, consoleId=ps$nali$console,session=ps$session)
  }
}

check.shiny.chunk = function(chunk.ind = ps$chunk.ind,...,session=ps$session, ps=get.ps(), internal=FALSE, max.lines=300, store.output=FALSE, input.code=NULL) {
  #cat("\n check.shiny.chunk1")
  if (!internal)
    set.shiny.chunk(chunk.ind, input.code=input.code)
  #cat("\n check.shiny.chunk2")
  #browser()
  restore.point("check.shiny.chunk")
  #cat("\n check.shiny.chunk3")
  #if (chunk.ind==2) {
  #    stop()
  #}

  
  if (isTRUE(ps$use.secure.eval)) {
    ret = secure.check.chunk(chunk.ind=chunk.ind,store.output=store.output)
    #cat("\nps:")
    #print(ps)
    #cat("\n",ps$failure.message)
    #ps = get.ps()
  } else {
    if (!is.false(ps$catch.errors)) {
      ret = tryCatch(check.chunk(chunk.ind=chunk.ind, store.output=store.output), error = function(e) {ps$failure.message <- as.character(e);return(FALSE)})
    } else {
      ret = check.chunk(chunk.ind=chunk.ind,store.output=store.output)
    }
  }
  

  ps$prev.check.chunk.ind = chunk.ind
  
  if (!ret)
    ps$cdt$is.solved[chunk.ind] = FALSE
  
  if (!internal) {
    if (!ret) {
      txt = merge.lines(c(ps$success.log, ps$failure.message))
      if (isTRUE(ps$current.hint.on.fail)) {
        hint.txt = tryCatch(merge.lines(capture.output(hint(ps=ps))),
         error = function(e) {merge.lines(as.character(e))})
        txt = paste0(txt,"\nHint:", hint.txt)
      } else {
        txt = paste0(txt,"\nPress the hint button to get a hint.")
      }
      updateAceEditor(ps$session, ps$nali$console, value=txt, mode="text")
      ps$cdt$is.solved[chunk.ind] = FALSE
    } else {
      #restore.point("success test shiny chunk")
      
      if (NROW(ps$chunk.console.out)>max.lines) {
        txt = merge.lines(
          c("You successfully solved the chunk!",
            ps$chunk.console.out[1:max.lines],
            paste0("\n...", NROW(ps$chunk.console.out)-max.lines," lines ommited...")))
      } else {
        txt = merge.lines(c("You successfully solved the chunk!",
                            ps$chunk.console.out))
      }
      updateAceEditor(ps$session, ps$nali$console, value=txt,mode="r")
      proceed.with.successfuly.checked.chunk(chunk.ind)
    }
  }

  #cat("\nend check.shiny.chunk.ui\n")
  return(ret)
}

proceed.with.successfuly.checked.chunk = function(chunk.ind, ps=get.ps()) {
  restore.point("proceed.with.successfuly.checked.chunk")

  ps$cdt$is.solved[chunk.ind] = TRUE
  
  # If we have precomp=TRUE, it is often sensible to replace 
  # user solution with sample solution 
  # A replace.sol chunk option takes precedence over global problem set option
  if (!is.null(ps$cdt$chunk.opt[[chunk.ind]][["replace.sol"]])) {
    replace.sol = ps$cdt$chunk.opt[[chunk.ind]][["replace.sol"]]
  } else {
    replace.sol = isTRUE(ps$replace.sol)
  }
  
  if (isTRUE(replace.sol)) {
    ps$cdt$stud.code[chunk.ind] = ps$cdt$sol.txt[chunk.ind]
  }
  
  if (is.last.chunk.of.ex(chunk.ind)) {
    ex.ind = ps$cdt$ex.ind[chunk.ind]
    if (!isTRUE(ps$precomp)) {
        # need to put env into a list,
        # since otherwise data.table throws strange error
        ps$edt$ex.final.env[[ex.ind]] = list(copy.stud.env(ps$stud.env))
    }
      
  }
  r.chunk.ui.mode = paste0("r.chunk_",chunk.ind,".ui.mode")
  ps$cdt$mode[[chunk.ind]]="output"
  update.chunk.ui(chunk.ind)


  # set the next chunk to edit mode
  if (chunk.ind < NROW(ps$cdt)) {
    if (ps$cdt$ex.ind[chunk.ind] == ps$cdt$ex.ind[chunk.ind+1] &
       !ps$cdt$is.solved[chunk.ind+1]) {

      #cat("update next chunk...")
      ps$cdt$mode[chunk.ind+1] = "input"
      update.chunk.ui(chunk.ind+1)
    }
  }

}


hint.shiny.chunk = function(chunk.ind, ...,session=ps$session, ps=get.ps()) {
  restore.point("hint.shiny.chunk")
  set.shiny.chunk(chunk.ind, ps=ps)
  envir=ps$stud.env; in.R.console=is.null(ps$nali$console)
  
  # If the current chunk has not been checked. Check it again
  #if (!identical(chunk.ind,ps$prev.check.chunk.ind))
  if (!isTRUE(ps$hint.noeval))
    check.shiny.chunk(chunk.ind, internal=TRUE)
  
  txt = tryCatch(merge.lines(capture.output(hint(ps=ps))),
         error = function(e) {merge.lines(as.character(e))})
  txt = paste0("Hint: ", txt)
  updateAceEditor(ps$session, ps$nali$console, value=txt, mode="text")
}

help.shiny.chunk = function(chunk.ind, range=NULL, selection="",...,session=ps$session, ps=get.ps()) {
  set.shiny.chunk(chunk.ind, cursor=range$start, selection=selection)
  envir=ps$stud.env; in.R.console=is.null(ps$nali$console)
  restore.point("help.shiny.chunk")

  if (ps$selection == "") {
    txt = sep.lines(ps$code)
    if (length(ps$cursor)>0) {
      txt = txt[ps$cursor$row+1]
      txt = word.at.pos(txt, pos=ps$cursor$column+1)
    }
  } else {
    txt = ps$selection
  }
  if (is.null(txt) | isTRUE(nchar(txt)==0)) {
    updateAceEditor(ps$session, ps$nali$console, value="No R command selected to show help for.", mode="text")
    return()
  }
  
  help = get.help.txt(txt)
  # To do: replace special characters in a better manner
  help = iconv(help, to='ASCII//TRANSLIT')
  #Encoding(help) = "UTF8"
  updateAceEditor(ps$session, ps$nali$console, value=help, mode="text")

  return()
}

restore.shiny.chunk = function(chunk.ind=ps$chunk.ind,...,session=ps$session,ps=get.ps()) {
  restore.point("restore.shiny.chunk")
  set.shiny.chunk(chunk.ind)

  ps$cdt$stud.code[[chunk.ind]] = ps$cdt$task.txt[[chunk.ind]]
  ps$cdt$is.solved[[chunk.ind]] = FALSE
  ps$stud.code = ps$cdt$stud.code[[chunk.ind]]

  updateAceEditor(ps$session, ps$nali$editor, value=ps$stud.code, mode="r")
  updateAceEditor(ps$session, ps$nali$console, value="restored original task code...", mode="text")
}


# Show sample solution
solution.shiny.chunk = function(chunk.ind=ps$chunk.ind,...,session=ps$session,ps=get.ps()) {
  restore.point("solution.shiny.chunk")
  set.shiny.chunk(chunk.ind)

  ps$cdt$stud.code[[chunk.ind]] = ps$cdt$sol.txt[[chunk.ind]]
  #ps$cdt$is.solved[[chunk.ind]] = FALSE
  ps$stud.code = ps$cdt$stud.code[[chunk.ind]]

  updateAceEditor(ps$session, ps$nali$editor, value=ps$stud.code, mode="r")
  updateAceEditor(ps$session, ps$nali$console, value="Sample solution shown", mode="text")
}


output.shiny.chunk = function(chunk.ind, ...,session=ps$session, ps=get.ps()) {
  restore.point("output.shiny.chunk")
  set.shiny.chunk(chunk.ind)
  update.chunk.ui(chunk.ind, mode="output")
}


edit.shiny.chunk = function(chunk.ind, ...,session=ps$session, ps=get.ps()) {
  restore.point("edit.shiny.chunk")
  #browser()
  if (can.chunk.be.edited(chunk.ind)) {
    update.chunk.ui(chunk.ind, mode="input")
    set.shiny.chunk(chunk.ind)
    session = ps$session
  } else {
    cdt = ps$cdt
    ck = cdt[chunk.ind,]
    nali = cdt$nali[[chunk.ind]]
    
    # Just run all required previous chunks
    num.prev.chunks = sum(cdt$ex.ind %in% ck$ex.ind & cdt$chunk.ps.ind < (ck$chunk.ps.ind) & cdt$optional == FALSE & !cdt$is.solved)
    
    use.sample.solution = isTRUE(ps$prev.chunks.sample.solution)
    
    tmsg = if (use.sample.solution) {
      paste0("Run all ", num.prev.chunks," required earlier chunks with sample solution...")
    } else {
      paste0("Try to run all ", num.prev.chunks," required earlier chunks...")
    }
    timedMessage(nali$alertOut, html=colored.html(tmsg,color = "#000088"), millis=Inf)

    res = run.required.previous.shiny.chunks(ps=ps, chunk.ind = chunk.ind,update.chunk.ui = TRUE, use.sample.solution = use.sample.solution)

    if (res$ok) {
      timedMessage(nali$alertOut, html=colored.html(paste0(tmsg, " success!"),color = "#000088"), millis=5000)
      # Don't run: otherwise code will vanish...
      #update.chunk.ui(chunk.ind, mode="input")
      #set.shiny.chunk(chunk.ind,input.code = ck$stud.code)
      
      # Scroll back to current chunk
      #evalJS(paste0('$("#',nali$chunkUI,'")[0].scrollIntoView();'))
      #js = paste0(';var pos = $("#',nali$chunkUI,'").offset();window.scrollTo(pos.left, pos.top);')
      #cat("\n",js)
      #evalJS(js)
  
    } else {
      fck = cdt[res$failed.chunk,]
      if (fck$ex.ind==ck$ex.ind) {
        loc.msg = paste0("in chunk no ", fck$chunk.ex.ind," of this exercise")
      } else {
        loc.msg = paste0("in chunk no ", fck$chunk.ex.ind," of  exercise ", ps$edt$ex.name[fck$ex.ind])
      }
      timedMessage(fck$nali[[1]]$alertOut, html=colored.html(paste0("Failure in this required chunk: ", ps$failure.message),color = "#880000"), millis=8000)

      timedMessage(nali$alertOut, html=colored.html(paste0("Failure ", loc.msg),color = "#880000"), millis=8000)
    }
    # timedMessage(nali$alertOut, html=colored.html(ps$failure.message,color = "#880000"), millis=5000)
  }
}

data.shiny.chunk = function(chunk.ind=ps$chunk.ind,session=ps$session,
                            ...,ps=get.ps()) {
  restore.point("data.shiny.chunk")
  set.shiny.chunk(chunk.ind, from.data.btn = TRUE)

  if (FALSE) {
    RRprofStart()
    update.data.explorer.ui()
    RRprofStop()
  # Uncomment to open the report
    RRprofReport()

    Rprof(tmp <- tempfile())
    update.data.explorer.ui()
    Rprof()
    summaryRprof(tmp)
    unlink(tmp)
  }
  update.data.explorer.ui()
  updateTabsetPanel(session, inputId="exTabsetPanel",
                    selected = "dataExplorerTabPanel")
}

save.shiny.chunk = function(chunk.ind=ps$chunk.ind,session=ps$session,...,ps=get.ps()) {
  restore.point("save.shiny.chunk")
  #set.shiny.chunk(chunk.ind)
  save.sav()
  nali = ps$cdt$nali[[chunk.ind]]
  timedMessage(nali$alertOut,"Your changes have been saved.", millis=2000)
  
  #createAlert(session, nali$alertOut,
  #  title = paste0("Saved as ", ps$sav.file),
  #  content = "",
  #  style = "info", append=FALSE
  #)
}


set.shiny.chunk = function(
  chunk.ind=NULL,selection=NULL, cursor=NULL,
  input=session$input,session=ps$session,
  ps=get.ps(),reload.env=FALSE, from.data.btn = FALSE,
  input.code=NULL
  ) {
  restore.point("set.shiny.chunk")
  #browser()
  #cat("start set.shiny.chunk\n")

  ps$selection = selection
  ps$cursor = cursor

  nali = ps$cdt$nali[[chunk.ind]]

  if (ps$cdt$mode[chunk.ind]=="input") {
    if (is.null(input.code)) {
      code = paste0(isolate(input[[nali$editor]]), collapse="\n")
    } else {
      code = input.code
    }
    ps$stud.code = ps$code = code
    ps$cdt$stud.code[[chunk.ind]] = code
  }
  restore.point("set.shiny.chunk2")

  ps$session = session
  ps$nali = nali
  # Always reload env if chunk.ind has changed
  if (!reload.env)
      reload.env = !isTRUE(ps$chunk.ind == chunk.ind)

  ps$chunk.ind = chunk.ind
  if (from.data.btn & ps$cdt$mode[chunk.ind]!="input") {
    reload.env = FALSE
    ps$stud.env = ps$cdt$stud.env[[ps$chunk.ind]]
  }

  if (reload.env) {
    stud.env = NULL
    if (!is.false(ps$catch.errors)) {
      tryCatch(
        stud.env <- make.chunk.stud.env(chunk.ind, ps),
        error = function(e) {
          ps$failure.message = paste0(deparse(e), collapse="\n")
        }
      )
    } else {
      stud.env <- make.chunk.stud.env(chunk.ind, ps)
    }
    if (!is.null(stud.env)) {
      ps$cdt[["stud.env"]][[ps$chunk.ind]] <- stud.env
    }
    if (is.null(stud.env)) {
      return(FALSE)
    }
    ps$stud.env = ps$cdt[["stud.env"]][[ps$chunk.ind]]
  }
  return(TRUE)
}




update.all.chunk.ui = function(ps=get.ps()) {
  restore.point("update.all.chunks")
  for (chunk.ind in ps$cdt$chunk.ps.ind) {
    update.chunk.ui(chunk.ind, ps=ps)
  }
}
skranz/RTutor documentation built on Feb. 7, 2024, 12:53 a.m.