Get synctex working

This commit is contained in:
James Allen
2014-06-30 18:35:01 +01:00
parent d3d18c384a
commit 11d951f021
8 changed files with 226 additions and 6 deletions

View File

@@ -27,4 +27,24 @@ div.full-size(
)
.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

View File

@@ -33,6 +33,9 @@ div.full-size(ng-controller="PdfController")
pdf-src="pdf.url"
key="project_id"
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")

View File

@@ -12,6 +12,7 @@ define [
onresize: () =>
console.log "Triggering", "layout:#{name}:resize", name
scope.$broadcast "layout:#{name}:resize"
repositionControls()
#maskIframesOnResize: true
# Restore previously recorded state
@@ -28,4 +29,13 @@ define [
# Save state when exiting
$(window).unload () ->
$.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
})
}

View File

@@ -95,6 +95,10 @@ define [
parts = path.split("/")
name = parts.shift()
rest = parts.join("/")
if name == "."
return @_findEntityByPathInFolder(folder, rest)
for entity in folder.children
if entity.name == name
if rest == ""
@@ -115,6 +119,26 @@ define [
if entity.children?
@_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) ->
# @forEachEntity (entity) ->
# if entity.type == "folder"

View File

@@ -16,3 +16,5 @@ define [
rawLog: ""
view: null # 'pdf' 'logs'
showRawLog: false
highlights: []
position: null

View File

@@ -2,7 +2,7 @@ define [
"base"
"libs/latex-log-parser"
], (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
$scope.$on "doc:opened", () ->
return if !autoCompile
@@ -59,8 +59,7 @@ define [
$scope.pdf.logEntryAnnotations = {}
for entry in logEntries.all
entry.file = entry.file.replace(/^(.*)\/compiles\/[0-9a-f]{24}\/(\.\/)?/, "")
entry.file = entry.file.replace(/^\/compile\//, "")
entry.file = normalizeFilePath(entry.file)
entity = ide.fileTreeManager.findEntityByPath(entry.file)
if entity?
@@ -84,6 +83,16 @@ define [
return ide.editorManager.getCurrentDocId()
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 = {}) ->
console.log "Recompiling", options
return if $scope.pdf.compiling
@@ -129,13 +138,115 @@ define [
controller: "ClearCacheModalController"
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) ->
$scope.openInEditor = (entry) ->
console.log "OPENING", entry.file, entry.line
entity = ide.fileTreeManager.findEntityByPath(entry.file)
return if entity.type != "doc"
return if !entity? or entity.type != "doc"
if entry.line?
line = entry.line
ide.editorManager.openDoc(entity, gotoLine: line)

View File

@@ -28,12 +28,16 @@ define [
return {
scope: {
"pdfSrc": "="
"highlights": "="
"position": "="
"dblClickCallback": "="
}
link: (scope, element, attrs) ->
pdfListView = new PDFListView element.find(".pdfjs-viewer")[0],
textLayerBuilder: TextLayerBuilder
annotationsLayerBuilder: AnnotationsLayerBuilder
highlightsLayerBuilder: HighlightsLayerBuilder
ondblclick: (e) -> onDoubleClick(e)
logLevel: PDFListView.Logger.DEBUG
pdfListView.listView.pageWidthOffset = 20
pdfListView.listView.pageHeightOffset = 20
@@ -58,6 +62,8 @@ define [
if (position = $.localStorage("pdf.position.#{attrs.key}"))
pdfListView.setPdfPosition(position)
scope.position = pdfListView.getPdfPosition(true)
$(window).unload () =>
$.localStorage "pdf.scale", {
scaleMode: pdfListView.getScaleMode()
@@ -69,7 +75,14 @@ define [
scope.flashControls = true
$timeout () ->
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) ->
if url
@@ -85,6 +98,35 @@ define [
initializePosition()
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 = () ->
pdfListView.setToFitHeight()

View File

@@ -112,4 +112,12 @@
position: relative;
}
}
.synctex-controls {
padding: 68px 2px 0;
.btn-xs {
line-height: 1.3;
padding: 0 2px 0;
}
}