Get synctex working
This commit is contained in:
@@ -27,4 +27,24 @@ div.full-size(
|
|||||||
)
|
)
|
||||||
|
|
||||||
.ui-layout-east
|
.ui-layout-east
|
||||||
include ./pdf
|
include ./pdf
|
||||||
|
|
||||||
|
.ui-layout-resizer-controls.synctex-controls(
|
||||||
|
ng-show="!!pdf.url"
|
||||||
|
ng-controller="PdfSynctexController"
|
||||||
|
)
|
||||||
|
a.btn.btn-default.btn-xs(
|
||||||
|
tooltip="Go to code location in PDF"
|
||||||
|
tooltip-placement="right"
|
||||||
|
tooltip-append-to-body="true"
|
||||||
|
ng-click="syncToPdf()"
|
||||||
|
)
|
||||||
|
i.fa.fa-long-arrow-right
|
||||||
|
br
|
||||||
|
a.btn.btn-default.btn-xs(
|
||||||
|
tooltip-html-unsafe="Go to PDF location in code<br/>(or double click PDF)"
|
||||||
|
tooltip-placement="right"
|
||||||
|
tooltip-append-to-body="true"
|
||||||
|
ng-click="syncToCode()"
|
||||||
|
)
|
||||||
|
i.fa.fa-long-arrow-left
|
||||||
@@ -33,6 +33,9 @@ div.full-size(ng-controller="PdfController")
|
|||||||
pdf-src="pdf.url"
|
pdf-src="pdf.url"
|
||||||
key="project_id"
|
key="project_id"
|
||||||
resize-on="layout:main:resize,layout:pdf:resize"
|
resize-on="layout:main:resize,layout:pdf:resize"
|
||||||
|
highlights="pdf.highlights"
|
||||||
|
position="pdf.position"
|
||||||
|
dbl-click-callback="syncToCode"
|
||||||
)
|
)
|
||||||
|
|
||||||
.pdf-uncompiled(ng-show="pdf.uncompiled && !pdf.compiling")
|
.pdf-uncompiled(ng-show="pdf.uncompiled && !pdf.compiling")
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ define [
|
|||||||
onresize: () =>
|
onresize: () =>
|
||||||
console.log "Triggering", "layout:#{name}:resize", name
|
console.log "Triggering", "layout:#{name}:resize", name
|
||||||
scope.$broadcast "layout:#{name}:resize"
|
scope.$broadcast "layout:#{name}:resize"
|
||||||
|
repositionControls()
|
||||||
#maskIframesOnResize: true
|
#maskIframesOnResize: true
|
||||||
|
|
||||||
# Restore previously recorded state
|
# Restore previously recorded state
|
||||||
@@ -28,4 +29,13 @@ define [
|
|||||||
# Save state when exiting
|
# Save state when exiting
|
||||||
$(window).unload () ->
|
$(window).unload () ->
|
||||||
$.localStorage("layout.#{name}", element.layout().readState())
|
$.localStorage("layout.#{name}", element.layout().readState())
|
||||||
|
|
||||||
|
repositionControls = () ->
|
||||||
|
state = element.layout().readState()
|
||||||
|
if state.east?
|
||||||
|
element.find(".ui-layout-resizer-controls").css({
|
||||||
|
position: "absolute"
|
||||||
|
right: state.east.size
|
||||||
|
"z-index": 10
|
||||||
|
})
|
||||||
}
|
}
|
||||||
@@ -95,6 +95,10 @@ define [
|
|||||||
parts = path.split("/")
|
parts = path.split("/")
|
||||||
name = parts.shift()
|
name = parts.shift()
|
||||||
rest = parts.join("/")
|
rest = parts.join("/")
|
||||||
|
|
||||||
|
if name == "."
|
||||||
|
return @_findEntityByPathInFolder(folder, rest)
|
||||||
|
|
||||||
for entity in folder.children
|
for entity in folder.children
|
||||||
if entity.name == name
|
if entity.name == name
|
||||||
if rest == ""
|
if rest == ""
|
||||||
@@ -115,6 +119,26 @@ define [
|
|||||||
if entity.children?
|
if entity.children?
|
||||||
@_forEachEntityInFolder(entity, callback)
|
@_forEachEntityInFolder(entity, callback)
|
||||||
|
|
||||||
|
getEntityPath: (entity) ->
|
||||||
|
@_getEntityPathInFolder @$scope.rootFolder, entity
|
||||||
|
|
||||||
|
_getEntityPathInFolder: (folder, entity) ->
|
||||||
|
for child in folder.children or []
|
||||||
|
if child == entity
|
||||||
|
return entity.name
|
||||||
|
else if child.type == "folder"
|
||||||
|
path = @_getEntityPathInFolder(child, entity)
|
||||||
|
if path?
|
||||||
|
return child.name + "/" + path
|
||||||
|
return null
|
||||||
|
|
||||||
|
getRootDocDirname: () ->
|
||||||
|
rootDoc = @findEntityById @$scope.project.rootDoc_id
|
||||||
|
return if !rootDoc?
|
||||||
|
path = @getEntityPath(rootDoc)
|
||||||
|
return if !path?
|
||||||
|
return path.split("/").slice(0, -1).join("/")
|
||||||
|
|
||||||
# forEachFolder: (callback) ->
|
# forEachFolder: (callback) ->
|
||||||
# @forEachEntity (entity) ->
|
# @forEachEntity (entity) ->
|
||||||
# if entity.type == "folder"
|
# if entity.type == "folder"
|
||||||
|
|||||||
@@ -16,3 +16,5 @@ define [
|
|||||||
rawLog: ""
|
rawLog: ""
|
||||||
view: null # 'pdf' 'logs'
|
view: null # 'pdf' 'logs'
|
||||||
showRawLog: false
|
showRawLog: false
|
||||||
|
highlights: []
|
||||||
|
position: null
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ define [
|
|||||||
"base"
|
"base"
|
||||||
"libs/latex-log-parser"
|
"libs/latex-log-parser"
|
||||||
], (App, LogParser) ->
|
], (App, LogParser) ->
|
||||||
App.controller "PdfController", ["$scope", "$http", "ide", "$modal", ($scope, $http, ide, $modal) ->
|
App.controller "PdfController", ["$scope", "$http", "ide", "$modal", "synctex", ($scope, $http, ide, $modal, synctex) ->
|
||||||
autoCompile = true
|
autoCompile = true
|
||||||
$scope.$on "doc:opened", () ->
|
$scope.$on "doc:opened", () ->
|
||||||
return if !autoCompile
|
return if !autoCompile
|
||||||
@@ -59,8 +59,7 @@ define [
|
|||||||
|
|
||||||
$scope.pdf.logEntryAnnotations = {}
|
$scope.pdf.logEntryAnnotations = {}
|
||||||
for entry in logEntries.all
|
for entry in logEntries.all
|
||||||
entry.file = entry.file.replace(/^(.*)\/compiles\/[0-9a-f]{24}\/(\.\/)?/, "")
|
entry.file = normalizeFilePath(entry.file)
|
||||||
entry.file = entry.file.replace(/^\/compile\//, "")
|
|
||||||
|
|
||||||
entity = ide.fileTreeManager.findEntityByPath(entry.file)
|
entity = ide.fileTreeManager.findEntityByPath(entry.file)
|
||||||
if entity?
|
if entity?
|
||||||
@@ -84,6 +83,16 @@ define [
|
|||||||
return ide.editorManager.getCurrentDocId()
|
return ide.editorManager.getCurrentDocId()
|
||||||
return null
|
return null
|
||||||
|
|
||||||
|
normalizeFilePath = (path) ->
|
||||||
|
path = path.replace(/^(.*)\/compiles\/[0-9a-f]{24}\/(\.\/)?/, "")
|
||||||
|
path = path.replace(/^\/compile\//, "")
|
||||||
|
|
||||||
|
rootDocDirname = ide.fileTreeManager.getRootDocDirname()
|
||||||
|
if rootDocDirname?
|
||||||
|
path = path.replace(/^\.\//, rootDocDirname)
|
||||||
|
|
||||||
|
return path
|
||||||
|
|
||||||
$scope.recompile = (options = {}) ->
|
$scope.recompile = (options = {}) ->
|
||||||
console.log "Recompiling", options
|
console.log "Recompiling", options
|
||||||
return if $scope.pdf.compiling
|
return if $scope.pdf.compiling
|
||||||
@@ -129,13 +138,115 @@ define [
|
|||||||
controller: "ClearCacheModalController"
|
controller: "ClearCacheModalController"
|
||||||
scope: $scope
|
scope: $scope
|
||||||
)
|
)
|
||||||
|
|
||||||
|
$scope.syncToCode = (position) ->
|
||||||
|
console.log "SYNCING VIA DBL CLICK", position
|
||||||
|
synctex
|
||||||
|
.syncToCode(position)
|
||||||
|
.then (data) ->
|
||||||
|
{doc, line} = data
|
||||||
|
ide.editorManager.openDoc(doc, gotoLine: line)
|
||||||
|
|
||||||
|
]
|
||||||
|
|
||||||
|
App.factory "synctex", ["ide", "$http", "$q", (ide, $http, $q) ->
|
||||||
|
synctex =
|
||||||
|
syncToPdf: (cursorPosition) ->
|
||||||
|
deferred = $q.defer()
|
||||||
|
|
||||||
|
doc_id = ide.editorManager.getCurrentDocId()
|
||||||
|
if !doc_id?
|
||||||
|
deferred.reject()
|
||||||
|
return deferred.promise()
|
||||||
|
doc = ide.fileTreeManager.findEntityById(doc_id)
|
||||||
|
if !doc?
|
||||||
|
deferred.reject()
|
||||||
|
return deferred.promise()
|
||||||
|
path = ide.fileTreeManager.getEntityPath(doc)
|
||||||
|
if !path?
|
||||||
|
deferred.reject()
|
||||||
|
return deferred.promise()
|
||||||
|
|
||||||
|
# If the root file is folder/main.tex, then synctex sees the
|
||||||
|
# path as folder/./main.tex
|
||||||
|
rootDocDirname = ide.fileTreeManager.getRootDocDirname()
|
||||||
|
if rootDocDirname? and rootDocDirname != ""
|
||||||
|
path = path.replace(RegExp("^#{rootDocDirname}"), "#{rootDocDirname}/.")
|
||||||
|
|
||||||
|
{row, column} = cursorPosition
|
||||||
|
|
||||||
|
$http({
|
||||||
|
url: "/project/#{ide.project_id}/sync/code",
|
||||||
|
method: "GET",
|
||||||
|
params: {
|
||||||
|
file: path
|
||||||
|
line: row + 1
|
||||||
|
column: column
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.success (data) ->
|
||||||
|
console.log "SYNCTEX RESPONSE", data
|
||||||
|
deferred.resolve(data.pdf or [])
|
||||||
|
.error (error) ->
|
||||||
|
deferred.reject(error)
|
||||||
|
|
||||||
|
return deferred.promise
|
||||||
|
|
||||||
|
syncToCode: (position, options = {}) ->
|
||||||
|
deferred = $q.defer()
|
||||||
|
if !position?
|
||||||
|
deferred.reject()
|
||||||
|
return deferred.promise()
|
||||||
|
|
||||||
|
# It's not clear exactly where we should sync to if it wasn't directly
|
||||||
|
# clicked on, but a little bit down from the very top seems best.
|
||||||
|
if options.includeVisualOffset
|
||||||
|
position.offset.top = position.offset.top + 80
|
||||||
|
|
||||||
|
$http({
|
||||||
|
url: "/project/#{ide.project_id}/sync/pdf",
|
||||||
|
method: "GET",
|
||||||
|
params: {
|
||||||
|
page: position.page + 1
|
||||||
|
h: position.offset.left.toFixed(2)
|
||||||
|
v: position.offset.top.toFixed(2)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.success (data) ->
|
||||||
|
console.log "SYNCTEX RESPONSE", data
|
||||||
|
if data.code? and data.code.length > 0
|
||||||
|
doc = ide.fileTreeManager.findEntityByPath(data.code[0].file)
|
||||||
|
return if !doc?
|
||||||
|
deferred.resolve({doc: doc, line: data.code[0].line})
|
||||||
|
.error (error) ->
|
||||||
|
deferred.reject(error)
|
||||||
|
|
||||||
|
return deferred.promise
|
||||||
|
|
||||||
|
return synctex
|
||||||
|
]
|
||||||
|
|
||||||
|
App.controller "PdfSynctexController", ["$scope", "synctex", "ide", ($scope, synctex, ide) ->
|
||||||
|
$scope.syncToPdf = () ->
|
||||||
|
synctex
|
||||||
|
.syncToPdf($scope.editor.cursorPosition)
|
||||||
|
.then (highlights) ->
|
||||||
|
$scope.pdf.highlights = highlights
|
||||||
|
|
||||||
|
$scope.syncToCode = () ->
|
||||||
|
synctex
|
||||||
|
.syncToCode($scope.pdf.position, includeVisualOffset: true)
|
||||||
|
.then (data) ->
|
||||||
|
{doc, line} = data
|
||||||
|
console.log "OPENING DOC", doc, line
|
||||||
|
ide.editorManager.openDoc(doc, gotoLine: line)
|
||||||
]
|
]
|
||||||
|
|
||||||
App.controller "PdfLogEntryController", ["$scope", "ide", ($scope, ide) ->
|
App.controller "PdfLogEntryController", ["$scope", "ide", ($scope, ide) ->
|
||||||
$scope.openInEditor = (entry) ->
|
$scope.openInEditor = (entry) ->
|
||||||
console.log "OPENING", entry.file, entry.line
|
console.log "OPENING", entry.file, entry.line
|
||||||
entity = ide.fileTreeManager.findEntityByPath(entry.file)
|
entity = ide.fileTreeManager.findEntityByPath(entry.file)
|
||||||
return if entity.type != "doc"
|
return if !entity? or entity.type != "doc"
|
||||||
if entry.line?
|
if entry.line?
|
||||||
line = entry.line
|
line = entry.line
|
||||||
ide.editorManager.openDoc(entity, gotoLine: line)
|
ide.editorManager.openDoc(entity, gotoLine: line)
|
||||||
|
|||||||
@@ -28,12 +28,16 @@ define [
|
|||||||
return {
|
return {
|
||||||
scope: {
|
scope: {
|
||||||
"pdfSrc": "="
|
"pdfSrc": "="
|
||||||
|
"highlights": "="
|
||||||
|
"position": "="
|
||||||
|
"dblClickCallback": "="
|
||||||
}
|
}
|
||||||
link: (scope, element, attrs) ->
|
link: (scope, element, attrs) ->
|
||||||
pdfListView = new PDFListView element.find(".pdfjs-viewer")[0],
|
pdfListView = new PDFListView element.find(".pdfjs-viewer")[0],
|
||||||
textLayerBuilder: TextLayerBuilder
|
textLayerBuilder: TextLayerBuilder
|
||||||
annotationsLayerBuilder: AnnotationsLayerBuilder
|
annotationsLayerBuilder: AnnotationsLayerBuilder
|
||||||
highlightsLayerBuilder: HighlightsLayerBuilder
|
highlightsLayerBuilder: HighlightsLayerBuilder
|
||||||
|
ondblclick: (e) -> onDoubleClick(e)
|
||||||
logLevel: PDFListView.Logger.DEBUG
|
logLevel: PDFListView.Logger.DEBUG
|
||||||
pdfListView.listView.pageWidthOffset = 20
|
pdfListView.listView.pageWidthOffset = 20
|
||||||
pdfListView.listView.pageHeightOffset = 20
|
pdfListView.listView.pageHeightOffset = 20
|
||||||
@@ -58,6 +62,8 @@ define [
|
|||||||
if (position = $.localStorage("pdf.position.#{attrs.key}"))
|
if (position = $.localStorage("pdf.position.#{attrs.key}"))
|
||||||
pdfListView.setPdfPosition(position)
|
pdfListView.setPdfPosition(position)
|
||||||
|
|
||||||
|
scope.position = pdfListView.getPdfPosition(true)
|
||||||
|
|
||||||
$(window).unload () =>
|
$(window).unload () =>
|
||||||
$.localStorage "pdf.scale", {
|
$.localStorage "pdf.scale", {
|
||||||
scaleMode: pdfListView.getScaleMode()
|
scaleMode: pdfListView.getScaleMode()
|
||||||
@@ -69,7 +75,14 @@ define [
|
|||||||
scope.flashControls = true
|
scope.flashControls = true
|
||||||
$timeout () ->
|
$timeout () ->
|
||||||
scope.flashControls = false
|
scope.flashControls = false
|
||||||
, 1000
|
, 1000
|
||||||
|
|
||||||
|
element.find(".pdfjs-viewer").scroll () ->
|
||||||
|
console.log "UPDATING POSITION", pdfListView.getPdfPosition(true)
|
||||||
|
scope.position = pdfListView.getPdfPosition(true)
|
||||||
|
|
||||||
|
onDoubleClick = (e) ->
|
||||||
|
scope.dblClickCallback?(page: e.page, offset: { top: e.y, left: e.x })
|
||||||
|
|
||||||
scope.$watch "pdfSrc", (url) ->
|
scope.$watch "pdfSrc", (url) ->
|
||||||
if url
|
if url
|
||||||
@@ -85,6 +98,35 @@ define [
|
|||||||
initializePosition()
|
initializePosition()
|
||||||
flashControls()
|
flashControls()
|
||||||
|
|
||||||
|
scope.$watch "highlights", (areas) ->
|
||||||
|
console.log "UPDATING HIGHLIGHTS", areas
|
||||||
|
return if !areas?
|
||||||
|
highlights = for area in areas or []
|
||||||
|
{
|
||||||
|
page: area.page - 1
|
||||||
|
highlight:
|
||||||
|
left: area.h
|
||||||
|
top: area.v
|
||||||
|
height: area.height
|
||||||
|
width: area.width
|
||||||
|
}
|
||||||
|
|
||||||
|
if highlights.length > 0
|
||||||
|
first = highlights[0]
|
||||||
|
pdfListView.setPdfPosition({
|
||||||
|
page: first.page
|
||||||
|
offset:
|
||||||
|
left: first.highlight.left
|
||||||
|
top: first.highlight.top - 80
|
||||||
|
}, true)
|
||||||
|
|
||||||
|
pdfListView.clearHighlights()
|
||||||
|
pdfListView.setHighlights(highlights, true)
|
||||||
|
|
||||||
|
setTimeout () =>
|
||||||
|
pdfListView.clearHighlights()
|
||||||
|
, 1000
|
||||||
|
|
||||||
scope.fitToHeight = () ->
|
scope.fitToHeight = () ->
|
||||||
pdfListView.setToFitHeight()
|
pdfListView.setToFitHeight()
|
||||||
|
|
||||||
|
|||||||
@@ -112,4 +112,12 @@
|
|||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.synctex-controls {
|
||||||
|
padding: 68px 2px 0;
|
||||||
|
.btn-xs {
|
||||||
|
line-height: 1.3;
|
||||||
|
padding: 0 2px 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user