diff --git a/packages/xod-arduino/src/index.js b/packages/xod-arduino/src/index.js index 47dc243a..1d0a70e5 100644 --- a/packages/xod-arduino/src/index.js +++ b/packages/xod-arduino/src/index.js @@ -3,6 +3,7 @@ export { transformProject, getNodeIdsMap, getNodePinKeysMap, + getTableLogNodeIds, getPinsAffectedByErrorRaisers, getRequireUrls, listGlobals, diff --git a/packages/xod-arduino/src/transpiler.js b/packages/xod-arduino/src/transpiler.js index 22dd542c..9e776b26 100644 --- a/packages/xod-arduino/src/transpiler.js +++ b/packages/xod-arduino/src/transpiler.js @@ -823,6 +823,17 @@ export const getNodePinKeysMap = def( ) ); +export const getTableLogNodeIds = def( + 'getNodeIdsMap :: TProject -> [NodeId]', + R.compose( + R.map(R.prop('originalId')), + R.filter( + R.compose(R.propEq('patchPath', XP.TABLELOG_NODETYPE), R.prop('patch')) + ), + R.prop('nodes') + ) +); + const getParentPatch = def( 'getParentPatch :: NodeId -> Patch -> Project -> Maybe Patch', (fullNodeId, rootPatch, project) => diff --git a/packages/xod-client-electron/src/view/containers/App.jsx b/packages/xod-client-electron/src/view/containers/App.jsx index 5e658710..1f9a5a7f 100644 --- a/packages/xod-client-electron/src/view/containers/App.jsx +++ b/packages/xod-client-electron/src/view/containers/App.jsx @@ -23,6 +23,7 @@ import { transpile, getNodeIdsMap, getNodePinKeysMap, + getTableLogNodeIds, getPinsAffectedByErrorRaisers, getRequireUrls, listGlobals, @@ -388,6 +389,7 @@ class App extends client.App { tProject => { const nodeIdsMap = getNodeIdsMap(tProject); const nodePinKeysMap = getNodePinKeysMap(tProject); + const tableLogNodeIds = getTableLogNodeIds(tProject); if (this.props.currentPatchPath.isNothing) return; const currentPatchPath = explodeMaybe( 'Imposible error: currentPatchPath is Nothing', @@ -412,6 +414,7 @@ class App extends client.App { client.createSystemMessage('Debug session started'), nodeIdsMap, nodePinKeysMap, + tableLogNodeIds, pinsAffectedByErrorRaisers, currentPatchPath, sessionGlobals, diff --git a/packages/xod-client/src/core/containers/App.jsx b/packages/xod-client/src/core/containers/App.jsx index f756ddc3..4a5d2239 100644 --- a/packages/xod-client/src/core/containers/App.jsx +++ b/packages/xod-client/src/core/containers/App.jsx @@ -29,6 +29,7 @@ import { transpile, getNodeIdsMap, getNodePinKeysMap, + getTableLogNodeIds, getPinsAffectedByErrorRaisers, listGlobals, extendTProjectWithGlobals, @@ -217,6 +218,7 @@ export default class App extends React.Component { code: transpile, nodeIdsMap: getNodeIdsMap, nodePinKeysMap: getNodePinKeysMap, + tableLogNodeIds: getTableLogNodeIds, tetheringInetNodeId: getTetheringInetNodeId, pinsAffectedByErrorRaisers: tProj => R.compose( @@ -233,6 +235,7 @@ export default class App extends React.Component { code, nodeIdsMap, nodePinKeysMap, + tableLogNodeIds, pinsAffectedByErrorRaisers, tetheringInetNodeId, }) => @@ -243,6 +246,7 @@ export default class App extends React.Component { ), nodeIdsMap, nodePinKeysMap, + tableLogNodeIds, code, pinsAffectedByErrorRaisers, sessionGlobals, diff --git a/packages/xod-client/src/debugger/actions.js b/packages/xod-client/src/debugger/actions.js index d259a2b7..b6ec1f24 100644 --- a/packages/xod-client/src/debugger/actions.js +++ b/packages/xod-client/src/debugger/actions.js @@ -34,6 +34,7 @@ export const startDebuggerSession = ( message, nodeIdsMap, nodePinKeysMap, + tableLogNodeIds, pinsAffectedByErrorRaisers, currentPatchPath, globals, @@ -44,6 +45,7 @@ export const startDebuggerSession = ( message, nodeIdsMap, nodePinKeysMap, + tableLogNodeIds, pinsAffectedByErrorRaisers, patchPath: currentPatchPath, globals, diff --git a/packages/xod-client/src/debugger/reducer.js b/packages/xod-client/src/debugger/reducer.js index f99d977c..30f8a571 100644 --- a/packages/xod-client/src/debugger/reducer.js +++ b/packages/xod-client/src/debugger/reducer.js @@ -1,5 +1,11 @@ import * as R from 'ramda'; -import { renameKeys, invertMap, foldMaybe, maybePath } from 'xod-func-tools'; +import { + renameKeys, + invertMap, + foldMaybe, + maybePath, + isAmong, +} from 'xod-func-tools'; import { ERROR_CODES } from 'xod-cloud-compile'; @@ -132,16 +138,70 @@ const addMessagesOrIncrementSkippedLines = R.curry( : addMessageListToDebuggerLog(logMessages, state) ); -const updateWatchNodeValues = R.curry((messageList, state) => { +const updateInteractiveNodeValues = R.curry((messageList, state) => { const MapToRekey = R.prop('nodeIdsMap', state); - return R.compose( - newValues => - R.over(R.lensProp('watchNodeValues'), R.merge(R.__, newValues), state), + // All node ids that is not represented in `tableLogNodeIds` is `watch` nodes + const [tableLogMessages, watchNodeMessages] = R.compose( + R.map(R.fromPairs), + R.partition(R.compose(isAmong(state.tableLogNodeIds), R.nth(0))), + R.toPairs, renameKeys(MapToRekey), - R.map(R.compose(R.prop('content'), R.last)), R.groupBy(R.prop('nodeId')), R.filter(R.propEq('type', UPLOAD_MSG_TYPE.XOD)) )(messageList); + + const updateWatchNodeValues = R.compose( + newValues => + R.over(R.lensProp('watchNodeValues'), R.merge(R.__, newValues)), + R.map(R.compose(R.prop('content'), R.last)) + )(watchNodeMessages); + + // Prepare data for table logs + const NEW_SHEET = String.fromCharCode(0xc); // TODO: Move somewhere + const newTableLogData = R.map( + R.compose( + R.reduce( + (acc, val) => + val === NEW_SHEET + ? R.append([], acc) + : R.over( + R.lensIndex(acc.length - 1), + R.append(R.split('\t', val)), + acc + ), + [[]] + ), + R.pluck('content') + ) + )(tableLogMessages); + + const updateTableLogs = R.compose( + R.map(([nodeId, [dataToLastSheet, ...newSheets]]) => + R.over( + R.lensProp(nodeId), + R.compose( + R.concat(R.__, newSheets), + sheets => + R.over( + R.lensIndex(sheets.length - 1), + R.concat(R.__, dataToLastSheet), + sheets + ), + R.when(R.isEmpty, R.append([])), + R.defaultTo([]) + ) + ) + ), + R.toPairs + )(newTableLogData); + + return R.compose( + updateWatchNodeValues, + R.over( + R.lensProp('tableLogValues'), + R.reduce((acc, fn) => fn(acc), R.__, updateTableLogs) + ) + )(state); }); /* eslint-disable no-bitwise */ @@ -431,7 +491,7 @@ export default (state = initialState, action) => { addErrorMessage, addMessagesOrIncrementSkippedLines(logMessages), updateInteractiveErroredNodePins(allMessages), - updateWatchNodeValues(allMessages) + updateInteractiveNodeValues(allMessages) )(state); } case LINE_SENT_TO_SERIAL: @@ -463,6 +523,7 @@ export default (state = initialState, action) => { R.assoc('isSkippingNewSerialLogLines', false), R.assoc('numberOfSkippedSerialLogLines', 0), R.assoc('nodeIdsMap', invertedNodeIdsMap), + R.assoc('tableLogNodeIds', action.payload.tableLogNodeIds), R.assoc('nodePinKeysMap', action.payload.nodePinKeysMap), rekeyAndAssocPinsAffectedByErrorRaisers( invertedNodeIdsMap, @@ -588,6 +649,7 @@ export default (state = initialState, action) => { R.assoc('isPreparingSimulation', false), R.assoc('isOutdated', false), R.assoc('uploadProgress', null), + R.assoc('tableLogNodeIds', action.payload.tableLogNodeIds), R.assoc('nodeIdsMap', invertedNodeIdsMap), R.assoc('nodePinKeysMap', action.payload.nodePinKeysMap), R.assoc('globals', action.payload.globals), diff --git a/packages/xod-client/src/debugger/state.js b/packages/xod-client/src/debugger/state.js index 36c57a93..ed4e5f0c 100644 --- a/packages/xod-client/src/debugger/state.js +++ b/packages/xod-client/src/debugger/state.js @@ -39,6 +39,10 @@ export default { currentStage: LOG_TAB_TYPE.COMPILER, nodeIdsMap: {}, watchNodeValues: {}, + tableLogNodeIds: [], + tableLogValues: { + // NodeId : [ /* Experiments history */ [[String]] ] + }, uploadProgress: null, interactiveErroredNodePins: {}, pinsAffectedByErrorRaisers: {}, diff --git a/packages/xod-client/src/editor/actions.js b/packages/xod-client/src/editor/actions.js index 275e54c7..7b541ca1 100644 --- a/packages/xod-client/src/editor/actions.js +++ b/packages/xod-client/src/editor/actions.js @@ -827,6 +827,7 @@ export const runSimulation = ( simulationPatchPath, nodeIdsMap, nodePinKeysMap, + tableLogNodeIds, code, pinsAffectedByErrorRaisers, globals, @@ -860,6 +861,7 @@ export const runSimulation = ( worker, nodeIdsMap, nodePinKeysMap, + tableLogNodeIds, pinsAffectedByErrorRaisers, patchPath: simulationPatchPath, globals, diff --git a/packages/xod-project/src/constants.js b/packages/xod-project/src/constants.js index cbba07ca..0f1f06b3 100644 --- a/packages/xod-project/src/constants.js +++ b/packages/xod-project/src/constants.js @@ -126,6 +126,7 @@ export const PULSE_CONST_NODETYPES = { }; export const WATCH_NODETYPE = 'xod/debug/watch'; +export const TABLELOG_NODETYPE = 'xod/debug/table-log'; // node types that prints values into Serial // to debug xod programm, it should be omitted @@ -138,6 +139,7 @@ export const DEBUG_NODETYPES = [ 'xod/core/console-log', WATCH_NODETYPE, 'xod/debug/console-log', + TABLELOG_NODETYPE, ]; /** diff --git a/packages/xod-project/src/internal/patchPathUtils.js b/packages/xod-project/src/internal/patchPathUtils.js index 32d45c65..2e7b1568 100644 --- a/packages/xod-project/src/internal/patchPathUtils.js +++ b/packages/xod-project/src/internal/patchPathUtils.js @@ -124,6 +124,9 @@ export const isTerminalPatchPath = R.test(terminalPatchPathRegExp); // :: String -> Boolean export const isWatchPatchPath = R.test(/^xod\/(core|debug)\/watch$/); +// :: String -> Boolean +export const isTableLogPatchPath = R.equals(CONST.TABLELOG_NODETYPE); + // :: String -> Boolean export const isJumperPatchPath = R.equals(CONST.JUMPER_PATCH_PATH); diff --git a/packages/xod-project/src/patchPathUtils.js b/packages/xod-project/src/patchPathUtils.js index 962808e1..6c80adf7 100644 --- a/packages/xod-project/src/patchPathUtils.js +++ b/packages/xod-project/src/patchPathUtils.js @@ -26,6 +26,7 @@ export { isValidPatchPath, isTerminalPatchPath, isWatchPatchPath, + isTableLogPatchPath, isFromBusPatchPath, isToBusPatchPath, isBusPatchPath,